共享对象 (★★) #shared-objects #memory-mgmt
概念与动机 共享对象提供了一种在同一应用服务器上跨用户会话和外部会话 共享数据的机制。与 ABAP 内存(仅限外部会话)或 SAP 内存(仅限平坦字段)不同,共享对象可以存储所有用户都可访问的复杂深层数据结构。
内存模型层次 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 应用服务器 ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 用户会话 A 用户会话 B │ │ ┌──────────────────────┐ ┌──────────────────────┐ │ │ │ 外部会话 1 │ │ 外部会话 1 │ │ │ │ ┌──────────────────┐ │ │ ┌──────────────────┐ │ │ │ │ │ 内部会话 │ │ │ │ 内部会话 │ │ │ │ │ │ + ABAP 内存 │ │ │ │ + ABAP 内存 │ │ │ │ │ └──────────────────┘ │ │ └──────────────────┘ │ │ │ │ SAP 内存 │ │ SAP 内存 │ │ │ └──────────────────────┘ └──────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ 共享内存(应用服务器级别) │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ │ │ 共享对象内存 │ │ │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │ │ │ │ │ │ │ 区域 1 │ │ 区域 2 │ │ 区域 N │ │ │ │ │ │ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ │ │ │ │ │ │ │ │ │ 根对象 │ │ │ │ 根对象 │ │ │ │ │ │ │ │ │ │ │ └──────────┘ │ │ └──────────┘ │ │ │ │ │ │ │ │ │ └──────────────┘ └──────────────┘ └─────────────┘ │ │ │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘
与其他内存机制的比较
特性
ABAP 内存
SAP 内存
共享对象
范围
一个外部会话
一个用户会话
应用服务器上所有用户
数据类型
任意
仅平坦字段
任意(必须在启用共享内存的类中)
持久性
直到会话关闭
直到注销
直到显式删除或服务器重启
跨用户?
否
否
是
大小限制
滚动区限制
较小(SPA/GPA)
每个区域可配置
区域类 共享对象被组织为区域 ,每个区域由一个区域类管理。
类
角色
创建者
CL_SHM_AREA
所有区域类的基类
SAP(框架)
区域类(如 ZCL_SHM_MY_AREA)
管理一个共享内存区域;通过事务 SHMA 生成
开发者(通过 SHMA)
区域句柄类
提供访问区域实例的句柄;与区域类一起自动生成
系统(自动生成)
数据/根类
包含作为属性的实际数据;由开发者创建
开发者
类关系 1 2 3 4 5 6 7 CL_SHM_AREA(SAP 基类) └── ZCL_SHM_MY_AREA(区域类,由 SHMA 生成) 提供:ATTACH_FOR_WRITE, ATTACH_FOR_READ, ATTACH_FOR_UPDATE, DETACH ZCL_MY_ROOT(数据类,由开发者创建) 包含:保存共享数据的属性 继承:无特殊要求(但必须兼容 SHM)
实现共享对象的步骤 步骤 1:定义共享内存区域(事务 SHMA)
操作
详情
事务
SHMA
区域名称
如 Z_SHM_CATALOG
属性
设置区域类名、根类、有效期、客户端依赖性
结果
生成区域类(如 ZCL_SHM_Z_SHM_CATALOG)和区域句柄类
步骤 2:创建根/数据类 1 2 3 4 5 6 7 8 9 10 11 CLASS zcl_catalog_root DEFINITION PUBLIC CREATE PUBLIC. PUBLIC SECTION. DATA: mt_products TYPE ztt_products, " 产品目录数据 mv_last_update TYPE timestampl. METHODS: load_data, get_product IMPORTING iv_id TYPE zproduct_id RETURNING VALUE(rs_product) TYPE zs_product. ENDCLASS.
根类及其属性中使用的所有类型必须
兼容 SHM 。这意味着:
不能引用不可 SHM 序列化的对象
不能使用标记为 NOT FOR SHARED OBJECTS 的类
所有引用的类型必须可在共享内存中使用
步骤 3:写入共享内存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 DATA: lo_area TYPE REF TO zcl_shm_z_shm_catalog, lo_root TYPE REF TO zcl_catalog_root. " 1. 附加以写入 lo_area = zcl_shm_z_shm_catalog=>attach_for_write( ). " 2. 在共享内存中创建根实例 CREATE OBJECT lo_root AREA HANDLE lo_area. " 3. 填充根对象数据 lo_root->load_data( ). " 4. 设置区域的根对象 lo_area->set_root( lo_root ). " 5. 分离(提交更改到共享内存) lo_area->detach( ).
步骤
方法
目的
附加
ATTACH_FOR_WRITE( )
获取区域写锁;返回区域句柄
创建根
CREATE OBJECT ... AREA HANDLE
在共享内存中实例化根类
设置根
area->set_root( root )
注册根对象为区域的根
分离
area->detach( )
释放锁;使更改对读者可见
步骤 4:从共享内存读取 1 2 3 4 5 6 7 8 9 10 11 12 13 14 DATA: lo_area TYPE REF TO zcl_shm_z_shm_catalog, lo_root TYPE REF TO zcl_catalog_root. " 1. 附加以读取 lo_area = zcl_shm_z_shm_catalog=>attach_for_read( ). " 2. 访问根对象 lo_root = lo_area->root. " 3. 使用数据 DATA(ls_product) = lo_root->get_product( iv_id = 'MAT01' ). " 4. 分离 lo_area->detach( ).
步骤
方法
目的
附加
ATTACH_FOR_READ( )
获取读锁;返回区域句柄
访问根
area->root
获取根对象的引用
分离
area->detach( )
释放读锁
附加模式比较
模式
锁类型
使用场景
并发访问
ATTACH_FOR_READ
读锁
读取数据
允许多个读者同时访问
ATTACH_FOR_WRITE
写锁
创建或替换整个区域内容
阻塞读者和写者
ATTACH_FOR_UPDATE
写锁
修改现有内容
阻塞读者和写者
读锁允许多个并发读者。写锁和更新锁是排他的。设计共享对象时应以读多写少为原则,以获得最佳性能。
典型使用场景 目录(读多改少)
方面
详情
模式
一次性加载(或按计划),由多个用户读取
写入触发
首次访问或定时刷新
读取频率
非常高(每次用户请求)
示例
产品目录、配置数据、汇率
1 2 3 4 5 6 7 8 写入者(管理员/调度器): ATTACH_FOR_WRITE → 加载数据 → 设置根 → DETACH ↓(共享内存已更新) 读取者(终端用户): ATTACH_FOR_READ → 访问根 → 获取数据 → DETACH ATTACH_FOR_READ → 访问根 → 获取数据 → DETACH ATTACH_FOR_READ → 访问根 → 获取数据 → DETACH ...(多个并发读者)
购物车(跨会话数据)
方面
详情
模式
每个用户有自己的区域实例(按键区分)
写入触发
用户添加/删除项目
读取频率
每用户访问
示例
购物车、用户偏好、会话状态
共享内存是单个应用服务器本地的。如果系统有多个应用服务器,在服务器 A 上写入的数据在服务器 B 上不可见 。跨服务器共享需要使用数据库表或其他持久化机制。
区域生命周期和失效
事件
行为
区域创建(首次写入)
分配内存,存储根对象
区域读取
返回引用;不复制数据
区域覆写
旧内容被替换;读者重新附加后获得新内容
区域失效
FREE_AREA 或 SHMA 事务;所有引用变为无效
服务器重启
所有共享内存被清除
1 2 " 使区域失效/释放 zcl_shm_z_shm_catalog=>free_area( ).
实现检查清单
步骤
事务/代码
完成?
1. 创建数据(根)类及其属性
SE24 / ADT
[ ]
2. 在 SHMA 中定义共享内存区域
SHMA
[ ]
3. 实现写入逻辑(附加 → 创建 → 设置 → 分离)
程序/方法
[ ]
4. 实现读取逻辑(附加 → 访问 → 分离)
程序/方法
[ ]
5. 处理异常(CX_SHM_* 类)
Try/catch 块
[ ]
常见异常
异常
原因
CX_SHM_NO_ACTIVE_VERSION
区域尚未写入数据
CX_SHM_EXCLUSIVE_LOCK_ACTIVE
另一个进程持有写锁
CX_SHM_CHANGE attempts
尝试修改读锁保护的数据
CX_SHM_VERSION_LIMIT_EXCEEDED
区域版本过多
考试/测试模式
关键词 / 模式
正确答案
共享对象范围
同一应用服务器 上的所有用户
定义区域的事务
SHMA
区域类的基类
CL_SHM_AREA
写入步骤
ATTACH_FOR_WRITE → CREATE OBJECT AREA HANDLE → set_root → DETACH
读取步骤
ATTACH_FOR_READ → 访问根 → DETACH
ATTACH_FOR_READ 锁定
允许多个读者并发
ATTACH_FOR_WRITE 锁定
排他 – 阻塞读者和写者
根类
开发者创建的类,以属性形式保存共享数据
跨服务器共享?
否 – 共享内存是每个应用服务器独立的
使用场景:目录
读多改少 – 共享对象的理想场景
使用场景:购物车
跨会话数据,按用户创建区域实例
FREE_AREA
使共享内存区域内容失效并删除
相关笔记
运行时与内存管理 – ABAP 内存、SAP 内存、会话架构
程序调用 – 内部会话及其与内存的关系
[[_posts/SAP_MM/SCM500_采购流程/00-仪表盘/考试陷阱]] – 常见共享内存陷阱
[[_posts/SAP_MM/SCM500_采购流程/00-仪表盘/快速参考]] – 内存区域比较表