Google Search - Blog...........

ABAP - Overcoming Memory Leaks With Mass BAPI Calls.

The Problem

It is known that some BAPI's can cause massive memory consumption when called 'en masse'. This is quite common in conversion projects. When you call one of those BAPI's let's say 500K times at a rate of 5000 times per hour the memory consumption can reach multiple Gigabytes easily. No need to say that this will dramatically decrease performance and will ultimately result in a short dump.

How to overcome this?
A practical solution


We somehow want to free up memory during the processing of our 500K records. When we use a REPORT with Selection-Screen as program for our BAPI calls we can call a new 'instance' of the program with the use of the SUBMIT statement. Normally this statement is used to call an other report. But we can also call the same report that executes the SUBMIT statement.
This approach can be run in the foreground as well as in back ground. If you start your initial program in background then all programs you start in there with SUBMIT will be implicitly also background processes .

When the new instance of the REPORT is called we somehow need to pass some parameters to it. At least the line number of the source file we are at now. With this the new instance of the report can start where the previous instance left off. This can easily be done with a Screen Variant. The big advantage is that you probably already are using a Selection-Screen in the report, so we are going to use this for parameter parsing.

In short this is the flow:
• Add a parameter p_recfrom to the Selection-Screen of the report.
• After every BAPI call we increase a counter
• When the counter reaches a certain level, let's say 1000 records, we call the FORM start_self_and_commit_suicide.
• In this FORM we:
update p_recfrom with 1 + the current line number of our source text file and save as Screen-Variant.

Call and start a new instance of our self (current report) with the Screen-Variant we just saved.

In the next chapter you will find a complete code example with ample comments.
Please refer to the example to see the above flow in practice.



The Coding
""""""""""""""""""""""""""""""""""
"Main program loop (example)
""""""""""""""""""""""""""""""""""
TRY.
DO.
"read next line from source textfile
PERFORM read_next_line CHANGING recnumber.

"convert the raw data into a useable struture
PERFORM structure_read_data USING CHANGING ls_strcut_data

"call the BAPI that's causing the headaches
PERFORM call_troubled_bapi USING ls_struct_data
"Increment record counter after every bapicall
"and after 1000 calls start new instance to free memory
recs_processed = recs_processed + 1.
IF recs_processesd > 1000.
PERFORM start_self_and_suicide.
ENDIF.
ENDDO.
CATCH cx_root.
"To stop DO loop at end of sourcefile
ENDTRY.

""""""""""""""""""""""""""""""""""
""""""""""""""""""""""""""""""""""
form start_self_and_suicide .
""""""""""""""""""""""""""""""""""
" Close all open file handles
CLOSE DATASET f_sourcefile.
CLOSE DATASET f_errorlog.
"""""""""""""""""""""""""""""""""""
" Save variant for job scheduling later
" to overcome memory shortages/leaks due to bapi-calls
" pass name of the Srceen Variant and nr of current record in source file
PERFORM save_variant USING recnumber gc_screenvariant .
"""""""""""""""""""""""""""""""""""
" Create new instance of current report (zadd_objlinks_2_dir
SUBMIT zadd_objlinks_2_dir USING SELECTION-SET gc_screenvariant USER sy-uname.
endform. " start_self_and_suicide
""""""""""""""""""""""""""""""""""

""""""""""""""""""""""""""""""""""
FORM save_variant USING i_screenvar_name i_van_recnr.
" If number of current record is not filled use
" the value from the screen
" (this happens at least when starting initial report)
IF i_van_recnr IS INITIAL.
i_van_recnr = frecsfrom.
ENDIF.
DATA line TYPE rsparams.
DATA it_param TYPE TABLE OF rsparams.
DATA jvt TYPE varit.
DATA: it_jvt TYPE TABLE OF varit.
DATA jvari LIKE varid.
CLEAR it_jvt.
""""""""""""""""""""""""""""""""""
" Fill some info for variant saving
jvari-report = sy-repid.
jvari-variant = i_screenvar_name.
jvari-ename = 'autom. generated variant'.
jvari-environmnt = 'A'.
jvari-mlangu = 'N'.
jvt-mandt = sy-mandt.
jvt-report = sy-repid.
jvt-variant = i_screenvar_name.
jvt-langu = sy-langu.
jvt-vtext = 'don''t delete'.
APPEND jvt TO it_jvt.
"""""""""""""""""""""""""""""
" Save each element of the selection-screen
" that has relevant data for the Screen variant
line-sign = 'I'.
line-option = 'EQ'.
line-kind = 'P'.
line-selname = 'FNAME'.
line-low = fname.
APPEND line TO it_param.
line-sign = 'I'.
line-option = 'EQ'.
line-kind = 'P'.
line-selname = 'FERROR'.
line-low = ferror.
APPEND line TO it_param.
line-sign = 'I'.
line-option = 'EQ'.
line-kind = 'P'.
line-selname = 'FRECSTOT'.
line-low = frecstot.
APPEND line TO it_param.
line-sign = 'I'.
line-option = 'EQ'.
line-kind = 'P'.
line-selname = 'FRECSVAN'.
line-low = van_recnr.
APPEND line TO it_param.
line-sign = 'I'.
line-option = 'EQ'.
line-kind = 'P'.
line-selname = 'FTESTRUN'.
line-low = ftestrun.
APPEND line TO it_param.
""""""""""""""""""""""""""""""""""""
" Delete old screen variant (if excists)
CALL FUNCTION 'RSAQ_DELETE_ONE_VARIANT'
EXPORTING
report = sy-repid
variant = gc_screenvariant "<-- constant with SV. name EXCEPTIONS not_authorized = 1 not_executed = 2 no_report = 3 report_not_existent = 4 report_not_supplied = 5 variant_locked = 6 OTHERS = 7. IF sy-subrc <> 0.
"TODO: error handling
ENDIF.
COMMIT WORK.
""""""""""""""""""""""""""""""""""""
" Create new variant with altered data
" (mainly the line/record number to start from
CALL FUNCTION 'RS_CREATE_VARIANT'
EXPORTING
curr_report = sy-repid
curr_variant = gc_screenvariant
vari_desc = jvari
TABLES
vari_contents = it_param
vari_text = it_jvt
* VSCREENS =
EXCEPTIONS
illegal_report_or_variant = 1
illegal_variantname = 2
not_authorized = 3
not_executed = 4
report_not_existent = 5
report_not_supplied = 6
variant_exists = 7
variant_locked = 8
OTHERS = 9
.
IF sy-subrc <> 0.
"TODO: error handling
ENDIF.

COMMIT WORK.
ENDFORM. " save_variant

No comments:

Post a Comment