Note: a more suitable name for this blog should be “DELETE itab statement and memory use” or “DELETE itab statement and memory deallocation”, because the Garbage Collector is not responsible for internal tables memory allocation. Thank Randolf Eilenberger for alerting me about this (see comments).
This week I had a problem regarding memory use in an ABAP program. While debugging the program with the Memory Analysis tool active, I found something that intrigues me. After a DELETE itab statement where 60% of the rows were deleted, instead of decreasing the memory use what happened was an increase of the memory use.
I never had the curiosity of analize the memory use behavior of program after a DELETE statement because I really believed that the DELETE statement and memory release were like synonyms. But unfortunately I was completely wrong.
Let me show you an example that i created for this blog.
As we can see, the memory used increased after the DELETE (note that the number of rows was reduced dramatically). So I decided to investigate it, and that’s why I’m here, writing this blog.
After a few tests I found a way to release the memory, by transfering the remaining rows to a auxiliary internal table, clearing the original internal table and transfering the content back to the original.
Let me show you the results.
As expected, at first we have an increase in the memory use
but after clearing the original table the memory use is reduced dramatically
I would like to know from the community if you have already noticed this behavior of the ABAP garbage collector.
Below is the source code of a method to release the memory allocated to an internal table (that is intended to be used after a delete of a reasonable number of rows).
METHODS: release_memory CHANGING ch_t_tab TYPE STANDARD TABLE.
METHOD release_memory. FIELD-SYMBOLS: <fs_table> TYPE STANDARD TABLE, <fs_line> TYPE ANY, <fs_tab_line> TYPE ANY. DATA: lo_struct_typ TYPE REF TO cl_abap_structdescr, lo_dyntable_typ TYPE REF TO cl_abap_tabledescr, lt_dyntable TYPE REF TO data, ls_dyntable TYPE REF TO data. READ TABLE ch_t_tab INDEX 1 ASSIGNING <fs_tab_line>. lo_struct_typ ?= cl_abap_typedescr=>describe_by_data( <fs_tab_line> ). lo_dyntable_typ = cl_abap_tabledescr=>create( p_line_type = lo_struct_typ ). CREATE DATA: lt_dyntable TYPE HANDLE lo_dyntable_typ, ls_dyntable TYPE HANDLE lo_struct_typ. ASSIGN: ls_dyntable->* TO <fs_line>, lt_dyntable->* TO <fs_table>. LOOP AT ch_t_tab ASSIGNING <fs_tab_line>. MOVE-CORRESPONDING <fs_tab_line> TO <fs_line>. APPEND <fs_line> TO <fs_table>. ENDLOOP. FREE ch_t_tab. ch_t_tab = <fs_table>. ENDMETHOD. "release_memory
Updated with a new example with the suggestion to call the garbage collector manually.
Result: starting the garbage collector after the DELETE statement doesn’t release memory, in fact it increase the memory used a little bit more…
Here’s a new example.
After Garbage Collection
After release memory method
Here’s a graph of another execution.