Skip to Content

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).

Hi All,

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.

scnblog04_01.JPG

before DELETE

scnblog04_02.JPG

after DELETE

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.


scnblog04_03.JPG

As expected, at first we have an increase in the memory use


scnblog04_04.JPG

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).


Method Definition

METHODS: release_memory CHANGING ch_t_tab TYPE STANDARD TABLE.



Method Implementation


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.

scnblog4_05.JPG

Before DELETE

scnblog4_06.JPG

After DELETE

scnblog4_07.JPG

After Garbage Collection

scnblog4_08.JPG

After release memory method

Here’s a graph of another execution.

scnblog4_09.JPG

Regards,

Christian


To report this post you need to login first.

17 Comments

You must be Logged on to comment or reply to a post.

  1. Jelena Perfiljeva

    Well, FREE certainly frees up memory (it’s in the documentation).

    I believe garbage collector runs only periodically, so you might not see an instant effect. Have you tried starting garbage collector manually?

    (0) 
  2. Christian Jianelli Post author

    Blog updated with the results of the suggestion of calling the garbage collector manually.

    Now it becomes even more interesting. Starting the garbage collector after the DELETE statement doesn’t release memory, in fact it increase the memory used a little bit more…

    Regards,

    Christian

    (0) 
  3. Former Member

    Hi Christian,

    The observed effects have nothing to do with the garbage collector – the GC is simply not responsible for the memory allocated by internal tables.

    Also, the DELETE statement on internal tables does not release any allocated memory. This can only be achieved with the FREE, or the CLEAR or REFRESH statements.

    The story would be even more puzzling, if internal table LT_EKKO_AUX is not filled with LOOP + APPEND, as in your example, but instead with a simple

    > LT_EKKO_AUX = LT_EKKO.

    This way, the allocated memory would not reduce at all after the sequence

    > FREE LT_EKKO.

    > LT_EKKO = LT_EKKO_AUX.

    > FREE LT_EKKO_AUX.

    The reason is the table sharing, that includes all allocated table pages – even if they are empty.

    Best Regards,

    Randolf

    (0) 
    1. Christian Jianelli Post author

      Hi Randolf,

      My first test was exactly this one, moving all content using lt_ekko_aux[] = lt_ekko[], that didn’t work. Searching the documentation I found the following explanation:

      Because internal tables and strings can become quite large, ABAP saves copying workload by employing a lazy copy strategy (Copy-On-Write). The initial sharing/revocation of initial sharing in static boxed components is analogous in its effect.

      As long as the component remains unchanged, ABAP lets all variables that refer to the table or string point to a single memory object. Only when a table or string is changed via a variable does the ABAP runtime make a separate copy of the changed object. This lazy copy strategy means that changes to tables, strings, or boxed components can result in surprising jumps in memory consumption, as seen in the Memory Inspector.

      Reference: http://help.sap.com/saphelp_nw70ehp2/helpdata/en/88/84fb5269d34838a1f119b41dcdbc57/frameset.htm

      Once the garbage collector is not responsible for the memory allocated by internal tables and the DELETE statement doesn’t release memory, if we need to release memory, we have to do manually right? (like I did)

      Thanks for your feedback.

      Regards,

      Christian

      (0) 
      1. Former Member

        Hi Christian,

        Yes, long living internal tables should be FREEd or CLEARed if their content is no longer needed. On the other hand, for a local variable the memory will be released automatically when the procedure is left.

        Best Regards,

        Randolf

        (0) 
      2. Puneet Desai

        Hello Christian,

        First of all thanks for such a nice blog.

        I just want to add that, to over come the Lazy copy strategy, instead of using a LOOP. ENDLOOP. you can also use following way

        LT_EKKO_AUX = LT_EKKO.

        APPEND INITIAL LINE TO LT_EKKO_AUX.

        This will be enough to force ABAP to allocate seperate memory to both the internal tables.

        (0) 
        1. Christian Jianelli Post author

          Hi Puneet,

          Thanks for the feedback.

          I’ve changed the release_memory method and the result was exactly the same but with better performance.

          New RELEASE_MEMORY method.

          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.

               ASSIGN: lt_dyntable->* TO <fs_table>.

               <fs_table> = ch_t_tab.

               APPEND INITIAL LINE TO <fs_table>.

               DELETE <fs_table> INDEX sytabix.

               FREE ch_t_tab.

               ch_t_tab[] = <fs_table>.

               FREE <fs_table>.

             ENDMETHOD.                    “release_memory

          Thanks!

          Best regards,

          Christian

          (0) 
    2. Christian Jianelli Post author

      Hi Randolf,
      I’ve found the documentation of the Garbage Collector, that says:

      garbage collector (BC-ABA)
      Deletes objects that are no longer referenced by object or data reference variables. The garbage collector is called periodically by the ABAP runtime environment. It follows reference variables of deleted objects. See also weak reference.

      Reference: http://help.sap.com/saphelp_glossary/en/35/26b214afab52b9e10000009b38f974/content.htm

      As you said, garbage collector has nothing to do with the memory allocation of internal tables.

      Thanks,

      Christian

      (0) 
      1. SeethaRamaiah Bharani

        Hi Christian,

        Great explanation.

        I am trying in my system and I am not getting correctly what you explained. After delete also it is having almost same memory i.e. Minor change in the memory. Do you miss any thing in the code part..

        BR,

        Bharani

        (0) 
        1. Christian Jianelli Post author

          Hi SeethaRamaiah,

          Thanks for your feedback.

          Sorry but I didn’t understand your question. Do you mean that after the method call the memory used still the same?

          Regards,

          Christian

          (0) 

Leave a Reply