值语义 (Value semantics) 和援用语义 (reference semantics) 形容了动态内存对象在多个变量援用它时, 能够体现的两种形式。
用于特定类型的动态内存对象的语义, 对该类型的对象如何耗费内存产生了重要影响。
实质上,应用值语义的援用变量总是有它本人的、它所援用的内存对象的惟一正本。值语义变量相似于动态变量;像动态变量一样,它间接绑定到它所代表的内存对象。只管变量只是一个援用,但在语义上它是内存对象自身。
相比之下,应用援用语义的援用变量被了解为指向内存对象的指针。内存对象在语义上独立于援用变量。该对象能够在许多这样的变量之间共享。
Value Semantics 的典型代表:
- ABAP Internal Tables
- Strings
- Boxed Components
应用值语义解析对 ABAP 内表、字符串或 boxed 组件的屡次援用。这意味着:
- 内表、字符串或 boxed 组件的每个变量都指向它本人的内存对象的独自正本。
- 将内表、字符串或 boxed 组件调配给第二个 ABAP 变量会触发对象的复制操作,以便每个变量都有本人的对象正本。
- 通过特定变量对内表、字符串或装箱组件所做的更改,对于已调配给同一对象的其余变量是不可见的。
因为外部表和字符串可能会变得十分大,ABAP 通过采纳 惰性复制
(有时也称为 写时复制
) 策略 (Copy-On-Write) 来节俭复制工作量。
咱们来看一个具体的例子。
源代码如下:
REPORT z.
DATA: lv_size TYPE abap_msize,
lv_size1 LIKE lv_size,
lv_consumed LIKE lv_size.
DATA: lt_table TYPE TABLE OF tadir,
lt_table1 LIKE lt_table.
SELECT * INTO TABLE lt_table FROM tadir.
cl_abap_memory_utilities=>get_total_used_size(IMPORTING size = lv_size).
WRITE:/ 'total consumed:' , lv_size.
lt_table1 = lt_table.
cl_abap_memory_utilities=>get_total_used_size(IMPORTING size = lv_size1).
lv_consumed = lv_size1 - lv_size.
WRITE:/ 'total consumed after =' , lv_consumed.
APPEND lt_table[1] TO lt_table.
CLEAR: lv_size.
cl_abap_memory_utilities=>get_total_used_size(IMPORTING size = lv_size).
lv_consumed = lv_size - lv_size1.
WRITE:/ 'total consumed after copy on write:', lv_consumed.
这个测试程序的 5 个关键点:
- 从数据库表
TADIR
里读取其全副数据,存储到内表 lt_table 内。打印以后应用程序所在的会话总共耗费的内存字节数。 - 将内表 lt_table 的内容复制给 lt_table1. 这里并不触发实在的内表间数据拷贝操作,因为内表 lt_table1 和 lt_table 此刻都指向同一块内存区域。
- 打印出以后应用程序所在的会话,同第一步执行结束后的内存增量。因为没有理论的数据拷贝操作,咱们能够判定,这个打印进去的值应该很小。
- 批改 lt_table 的值,之后,两个内表指向的内存区域不再是同一块,触发了 ABAP 的写时拷贝逻辑,造成了理论的内表拷贝操作,引起了大量的内存调配。
- 打印出第四步执行完后的应用程序内存增量。能够判定,因为
TADIR
数据库的全部内容从一个内表复制到另一个内表,因而这个增量的值和第一个步骤打印的值十分靠近。