Clean up dynamically allocated memory
- Last Updated: January 16, 2024
- 3 minute read
- OpenEdge
- Version 12.8
- Documentation
When you run a procedure with only static objects, these objects come and go with the procedure
that defines them. Because the AVM can see the individual DEFINE
statements for the objects, it knows when to create them, when they go out of scope, and
when to delete them. You do not have to worry about deleting them because The AVM does
it automatically for you.
The same is true, incidentally, of handles for static objects. When you store the handle
of a static object in a HANDLE variable, that value is just a pointer
to the object. It does not extend or affect the scope of the static object in any way.
The variable itself, because it is defined statically, is also deleted by the AVM when
its procedure goes out of scope.
When you create dynamic objects, however, the AVM cannot control their scope or their lifetime. If you create a dynamic object inside a loop, ABL might have no way of knowing at compile time how many of those objects the procedure will create. If you pass the handle of an object as a parameter to another procedure, ABL has no way of knowing at compile time where the handle came from, what it will be used for, or when the object it represents can safely be deleted. This is why you are responsible for taking care of this.
To see a dramatic example of the importance of memory management:
- Open the h-DeleteObject.p procedure used earlier and comment
out the statements that delete the dynamic query and buffer objects at the end of
the loop:
/* h-DeleteObject.p */ DEFINE VARIABLE hQuery AS HANDLE NO-UNDO. DEFINE VARIABLE hBuffer AS HANDLE NO-UNDO. DEFINE VARIABLE iCount AS INTEGER NO-UNDO. ETIME(TRUE). DO iCount = 1 TO 100: FOR EACH _file WHERE _file-num > 0 AND _file-num < 32000: CREATE QUERY hQuery. CREATE BUFFER hBuffer FOR TABLE _file._file-name. hQuery:SET-BUFFERS(hBuffer). hQuery:QUERY-PREPARE("FOR EACH " + _file._file-name). hQuery:QUERY-OPEN(). hQuery:GET-FIRST(). hQuery:QUERY-CLOSE(). // DELETE OBJECT hQuery. // DELETE OBJECT hBuffer. END. END. MESSAGE "100 iterations took " ETIME "milliseconds" VIEW-AS ALERT-BOX. - Bring up the Windows Task Manager, select the
Details tab, and find the running executable called
prowin.exe:
- Run the procedure, and watch the memory go:
After just 1000 iterations of this loop, which only created two dynamic objects, you have lost 839 megabytes of memory! Not only that, but even though you removed two key statements from the procedure, it ran slower:
The reason for this is that all that extra memory allocation is getting in the way of your procedure running efficiently. So you pay a heavy price all the way around.
Use the DELETE OBJECT statement to get rid of the memory for any dynamic
object, regardless of its type. To summarize, you use a CREATE QUERY
statement to create a dynamic query, a CREATE BUTTON statement to
create a dynamic button, and a CREATE BROWSE statement to create a
dynamic browse, but you use the DELETE OBJECT statement to clean up
each of them.
You must also remember to clean up persistent procedures when you are done with them.
Every time you execute a statement of the RUN procedure-name
PERSISTENT SET proc-handle form, you are also allocating
memory for the procedure and all its contents. You need to delete the procedure, when
you are done with it, with the DELETE PROCEDURE statement.