Memory Allocation - is there implicit release methods?

We recently ran into the odd issue with Natural programs on Windows.

It appears that when a dynamic object array is passed as a parameter, and then resized to zero to be re-used later, the memory is not properly released.

For example:
In Class ‘TEST-OBJ’ I have ‘TESTOBJ’ defined as

DEFINE DATA LOCAL
 1 #TESTOBJ
   2 STRING (A256)
   2 DATE (N8)
END-DEFINE

If I create a dynamic array of this object

1 #OBJ-ARR (1:*) HANDLE OF OBJECT

And call a series of objects from our db, adding them one at a time to the dynamic object array, I will expand the array by one each time prior to adding the object

#hi := *occ(#OBJ-ARR(*))
add 1 to #hi
expand array #OBJ-ARR to (1: #hi)
#OBJ-ARR(#hi) := #TEST-OBJ

When I have completed using this array completely, I reduce the array to zero before making new calls for new objects.

reduce array #OBJ-ARRAY to 0

We recently upgraded from Natural 6.3 to 8.4, and found that this caused an unfortunate error in our programs (-1). The solution appears to be through setting each object index to null prior to collapsing the dynamic array, or by forcing the program to slow down through interjecting a wait period between the re-use of the dynamic array. This implies to me that there is a buffer release action which applies following ‘reduce array to 0’, however it may not be operating consistently if the object array is reduced and re-expanded very quickly.

Does Natural for Windows have any sort of implicit or explicit garbage collection, similar to Java? For example, if I took the above code and segregated it in a specific ‘call method’ execution but where it returns the object array, would setting ‘reduce array to 0’ implicitly free up the memory space when it is returned? Is there a specific explicit method I can call which simplifies the memory release of allocated (large) dynamic object arrays (rather than looping through the array to set each object to null - bleh)?

You can force a certain amount of Natural house-keeping by issuing a LOGON command, but this is of no use to you because you would need to re-invoke the class, which you could do without the LOGON.

The need to reset the array’s entries might be a bug with Class objects. The technique appears to work for Programs in Nat 8.4.1. Submit an inquiry to SAG support

If clearing the array is necessary, do that with a single statement rather than a loop.

RESET #OBJ-ARRAY (*)
REDUCE ARRAY #OBJ-ARRAY TO 0

That is very possible. When performing the import with SYSMAIN from our testing server where we didn’t have this issue, we performed CATALL but didn’t explicity restow the classes. I have gone through each library to restow the classes, just in case.

I agree with using RESET as a simpler release method, I will implement it as an inexpensive safegaurd.

Thanks!

As an update to this topic. We opened a support case with Software AG as we have demonstrated the following.

Defining a dynamic array of objects like:
#objects(*) handle of object

and passing it as a parameter to a sub-program, where that subprogram contains
reduce array #objects to 0

may (1/100,000 times) cause a Natural Error (-1) due to an unfortunate memory issue when passing high throughput of Class IDs between Natural and Windows. This was not present in Nat 6.3 due to a different Windows architecture in the compiler.

A fix for Nat 8.1 was issued in November 2018 (Fix pack 20) which improved stability as long as “reduce array #objects to 0” is called in the same program that the dynamic object array is defined.

We are still waiting on a fix from development for subprograms which reduce object arrays to 0.

To close this topic, we heard back from Software Ag and they fixed the issue definitively as of Fix Pack 27 (For Natural 8.4.1) released in July 2019 (~ 1 year after opening the support ticket). This fix was also pushed into Nat 9.1.1 at that time.

The exact issue was with the compiler (Visual Studio 2015) used when shifting from 8.3.7 to 8.3.8 and onward. Some libraries in VS2015 used newer C/C++ runtime libraries which were not properly cleaning up memory.

As an aside, I have noticed that creating an object handle array and then calling:

reduce array object-array-list to 0

Does NOT release the memory of those objects even after these fix packs are applied. You MUST set the object array elements to null-handle in order to clear the memory space.

object-array-list(*) := null-handle