Focus areas when troubleshooting memory leaks in ABL applications:
- Classic ABL widgets (handle based)
- Object Oriented programming (class based)
- .NET objects
- ABL code running under PASOE
For basic information on memory management in ABL read the following Article:
Depending on the focus area that you wish to hone in on, skip to the required section below:
Classic ABL widgets (handle based)
Handle based widgets are anything in the ABL that is not a class or .NET. Examples of these are: persistent procedures, dynamic queries, dynamic buffers, datasets & sockets.
Handle based widgets do not participate in automatic garbage collection like class based objects do. As such, it is your responsibility to delete the handle when you are done with it.
When troubleshooting handle based widgets, start with the following Article which explains:
- How to use the -yx client startup parameter and SHOW-STATS statement to log data to proc.mon and client.mon files.
- This data is analyzed for memory increases over time (multiple iterations of the same set of steps) to first ensure that there is an apparent leak and the memory requirement is not due to normal increases in memory we use until we come to a levelling off point.
Once a memory leak is confirmed, use the following Articles to focus in on the leak.
1.
How to check for leaked dynamic objects programmatically?
- The code example in this Article shows how to walk the widget trees available in the SESSION object handle and dump information out for each entry on the widget tree
- This code can be invoked at any time in the application when current information is needed.
- Use the code example in this Article to walk the widget tree of dynamic objects that have been leaked by the session, if you believe the leak is confined to any of the following:
- Dynamic Buffers
- DataSets
- Data Sources
- Persistent Procedures
- Dynamic Queries
- Server Handles (to AppServer, Web Services, PASOE)
- Sockets (client or server)
2.
How to detect ABL Memory Leaks with Dynamic Objects Logging
- Use 4GLTrace and DynObjects.* client logging described in this Article, if you are uncertain what is causing the leak.
- There is a code example attached to this Article which parses the output log file and generates a report showing where the leaks are which need further investigation.
Object Oriented programming (class based)
- Memory leaks for class based objects are typically caused by circular references or lost references (where no variable points to the object).
- To detect these leaks use the following Article to enable DynObjects.Class logging
- Once logging has been enabled and the leak has been reproduced, use the code example attached to this Article to parse the output log file and generate a report showing where the leaks are found.
- How to detect ABL Memory Leaks with Dynamic Objects Logging
.NET objects
- .NET objects are garbage collected automatically by the .NET runtime.
- Please note that you cannot force .NET to actually garbage collect anything even when using System.GC:Collect().
- The .NET runtime engine prefers to delay collection as long as possible. This means that an application using .NET can show increased memory usage that may appear like a leak but really is not.
- The ABL process has no control over when the .NET Garbage Collector does its work
- How to force application garbage collection?
ABL code running under PASOE
OpenEdge 11.7.3 introduced the new "TRACKING ABL OBJECTS" REST API to track memory leaks in an ABL application, further enhanced in 11.7.4 and later versions:
Details on the REST API can also be found in the documentation:
There is also an equivalent "trackABLObjects" OEJMX operation:
Alternatively enable
DynObjects.* logging for the PAS for OE instance:
Once logging has been enabled and the leak has been reproduced use the code example in the following article to parse the PASOE instances agent.log file:
OpenEdge.Core.Util.LeakCheck classIn OE 12.6 the OpenEdge.Core.Util.LeakCheck class was added to support internal testing.
For more details see article:
How to use the OpenEdge.Core.Util.LeakCheck class ?