It is a well known fact, that you release the memory occupied by an internal table using either CLEAR or FREE, where FREE releases also the initial memory area. You normally use CLEAR, if you want to reuse the table and you use FREE, if you really want to get rid of it and don't want to refill it later on. Assigning an initial internal table to a filled internal table does also release the target table's memory in the same way as CLEAR does.
But last week a colleague pointed out to me that it is not such a well known fact that deleting lines of internal tables with DELETE normally does not release the memory occupied by the deleted lines. Instead, there seem to be people deleting lines of internal tables in order to release memory. Therefore as a rule:
Deleting lines of an internal table using the DELETE stament does not release the table's memory.
For an internal table that was filled and where all lines are deleted using the DELETE statement the predicate IS INITIAL in fact is true. But the internal table is only initial regarding the number of lines but not regarding the memory occupied. You can check that easily using the memory analysis tools of the ABAP debugger.
So far so good. For releasing the memory of an internal table you use CLEAR or FREE and you do not simply DELETE all lines.
But what about the use case, where you want to delete almost all lines from a big internal table and to keep the rest? After deleting, the internal table occupies much more memory than needed for its actual lines. If memory consumption is critical, you might want to get rid of the superfluous memory occupied by such an internal table. How to do that?
Spontaneous idea:
DELETE almost_all_lines_of_itab.
DATA buffer_tab LIKE itab.
buffer_tab = itab.
CLEAR itab.
itab = buffer_tab.
CLEAR buffer_tab.
Bad idea! Check it in the ABAP Debugger. Due to table sharing, after assigning itab to buffer_tab, buffer_tab is pointing to the same memory area as itab. Assigning buffer_tab back to itab after clearing itab is simply an effectles roundtrip and you gain nothing.
Improved idea:
DELETE almost_all_lines_of_itab.
DATA buffer_tab LIKE itab.
buffer_tab = VALUE #( ( LINES OF itab ) ).
CLEAR itab.
itab = buffer_tab.
CLEAR buffer_tab.
Now it works! Instead of copying itab to buffer_tab you can transfer the lines of itab sequentially to the initial target table and the memory is not shared. Before 7.40, SP08 you have to use INSERT LINES OF itab INTO TABLE buffer_tab instead of the VALUE expression, of course.
What also works for the use case is:
DELETE almost_all_lines_of_itab.
DATA buffer_tab LIKE itab.
buffer_tab = itab.
INSERT dummy_line INTO TABLE buffer_tab.
DELETE buffer_tab WHERE table_line = dummy_line.
CLEAR itab.
itab = buffer_tab.
CLEAR buffer_tab.
By inserting a dummy line into buffer_tab and deleting it again, the table sharing is canceled and buffer_tab is built from scratch (but only, if it needs considerably less memory than before; otherwise it is copied and nothing is gained again).
Ingenious minds might also find the following ways:
DELETE almost_all_lines_of_itab.
DATA buffer_string TYPE xstring.
EXPORT itab TO DATA BUFFER buffer_string.
CLEAR itab.
IMPORT itab FROM DATA BUFFER buffer_string.
CLEAR buffer_string.
or even
DELETE almost_all_lines_of_itab.
CALL TRANSFORMATION id SOURCE itab = itab
RESULT XML DATA(buffer_string).
CLEAR itab.
CALL TRANSFORMATION id SOURCE XML buffer_string
RESULT itab = itab.
CLEAR buffer_string.
Yes, those work too, but put some GET RUN TIME FIELD statements around them to see that those are not the best ideas.
But last week a colleague pointed out to me that it is not such a well known fact that deleting lines of internal tables with DELETE normally does not release the memory occupied by the deleted lines. Instead, there seem to be people deleting lines of internal tables in order to release memory. Therefore as a rule:
Deleting lines of an internal table using the DELETE stament does not release the table's memory.
For an internal table that was filled and where all lines are deleted using the DELETE statement the predicate IS INITIAL in fact is true. But the internal table is only initial regarding the number of lines but not regarding the memory occupied. You can check that easily using the memory analysis tools of the ABAP debugger.
So far so good. For releasing the memory of an internal table you use CLEAR or FREE and you do not simply DELETE all lines.
But what about the use case, where you want to delete almost all lines from a big internal table and to keep the rest? After deleting, the internal table occupies much more memory than needed for its actual lines. If memory consumption is critical, you might want to get rid of the superfluous memory occupied by such an internal table. How to do that?
Spontaneous idea:
DELETE almost_all_lines_of_itab.
DATA buffer_tab LIKE itab.
buffer_tab = itab.
CLEAR itab.
itab = buffer_tab.
CLEAR buffer_tab.
Bad idea! Check it in the ABAP Debugger. Due to table sharing, after assigning itab to buffer_tab, buffer_tab is pointing to the same memory area as itab. Assigning buffer_tab back to itab after clearing itab is simply an effectles roundtrip and you gain nothing.
Improved idea:
DELETE almost_all_lines_of_itab.
DATA buffer_tab LIKE itab.
buffer_tab = VALUE #( ( LINES OF itab ) ).
CLEAR itab.
itab = buffer_tab.
CLEAR buffer_tab.
Now it works! Instead of copying itab to buffer_tab you can transfer the lines of itab sequentially to the initial target table and the memory is not shared. Before 7.40, SP08 you have to use INSERT LINES OF itab INTO TABLE buffer_tab instead of the VALUE expression, of course.
What also works for the use case is:
DELETE almost_all_lines_of_itab.
DATA buffer_tab LIKE itab.
buffer_tab = itab.
INSERT dummy_line INTO TABLE buffer_tab.
DELETE buffer_tab WHERE table_line = dummy_line.
CLEAR itab.
itab = buffer_tab.
CLEAR buffer_tab.
By inserting a dummy line into buffer_tab and deleting it again, the table sharing is canceled and buffer_tab is built from scratch (but only, if it needs considerably less memory than before; otherwise it is copied and nothing is gained again).
Ingenious minds might also find the following ways:
DELETE almost_all_lines_of_itab.
DATA buffer_string TYPE xstring.
EXPORT itab TO DATA BUFFER buffer_string.
CLEAR itab.
IMPORT itab FROM DATA BUFFER buffer_string.
CLEAR buffer_string.
or even
DELETE almost_all_lines_of_itab.
CALL TRANSFORMATION id SOURCE itab = itab
RESULT XML DATA(buffer_string).
CLEAR itab.
CALL TRANSFORMATION id SOURCE XML buffer_string
RESULT itab = itab.
CLEAR buffer_string.
Yes, those work too, but put some GET RUN TIME FIELD statements around them to see that those are not the best ideas.
No comments:
Post a Comment