Reputation: 83
I recently issued an update to a HOST Reporting program. Our shop uses Enterprise PLI.
I added 2 new structures Declared as BASED. So i basically use an ALLOC statement to allocate the required storage for the structures and then pass the pointers to a Fetchable to get some details i need.
It failed with a storage error during a pilot run in production (LEMSG below). It was trying to process more than a million records there and it appears the job basically ran out of storage.
IBM0451S ONCODE=451 The STORAGE condition was raised.
From entry point MXXX at compile unit offset +000001EA at entry offset
More Details: IBM0451S
As a fix , i am issuing an update to explicitly add a FREE for the storage after the Fetchable call and i also updated the REGION PARM of my JCL to 0M.
Thought i'd check if you have seen this kind of errors before and have any additional thoughts. Thanks.
Here is how my latest updated code looks like
DECLARES
=======================================
DCL
01 IN_DATA BASED(IN_PTR),
% INCLUDE SYSLIB(XXXXXPAA);
DCL
01 OUT_DATA BASED(OUT_PTR),
% INCLUDE SYSLIB(YYYYYPAA);
DCL
01 IN_PTR PTR;
DCL
01 OUT_PTR PTR;
======================================
The below block of code runs for every record that get processed. The
FREE statement is what i now added. I was thinking that because i did
not have a FREE before , the ALLOC was basically getting new STOARGE
everytime it executed that block of code and ran out of storage.
ALLOC IN_DATA;
ALLOC OUT_DATA;
IN_DATA = '';
OUT_DATA = '';
IN_DATA.CODE = 'XXX';
CALL FABCD(IN_PTR,
OUT_PTR);
IF OUT_DATA.RTRN_CD <= 04 THEN
DETAIL_REC.XYZ = OUT_DATA.YYY_CODE;
ELSE
;
FREE IN_DATA; -------->> What i added now
FREE OUT_DATA; -------->> What i added now
=============================================
Upvotes: 2
Views: 519
Reputation: 2735
Apart from the storage problem point of view, allocating and freeing storage for each and every record processes is ahuge perforance killer.
From the snipped you show, it is not clear to be a) why you ALLOC in the first place, and b) why you think you need a fresh piece of storage for each record.
Just allocte the structures locally, the pass a pointer to them to the function.
DCL 01 IN_DATA,
% INCLUDE SYSLIB(XXXXXPAA);
DCL 01 OUT_DATA,
% INCLUDE SYSLIB(YYYYYPAA);
DCL IN_PTR PTR INIT ( ADDR( IN_DATA) );
DCL OUT_PTR PTR INIT ( ADDR( OUT_DATA ) );
This will have PL/I allocate the structures only once, but still allow pointers to the storage be passe to the function routine.
I would also remove the second performance killer: The probably unneeded initialization of the structures
IN_DATA = ‘‘;
OUT_DATA = ‘‘;
This does a field by field initialization. Don‘t do this unless you have good reason.
Upvotes: 2
Reputation: 10765
This is expected behavior. From your description, your initial code had a memory leak, allocating storage without freeing it. Now that you have added code to free the allocated memory when it is no longer needed, you likely don't need the REGION=0M, though as indicated in a comment it may not be doing what you wanted anyway.
Upvotes: 0