To force garbage collection of .Net objects:
System.GC:Collect().
System.GC:WaitForPendingFinalizers().
System.GC:Collect().
- An ABL process has no control over when the .NET Garbage Collector does its work.
- .Net garbage collection is performed asynchronously in another thread and is delayed until there are enough objects to collect.
- With ABL garbage collection there is no way to directly force this to happen with ABL code.
- It is advisable to upgrade to at least OpenEdge 11.7.4 where more recent fixes for references to .Net objects are when deleting ABL classes to be available for garbage collection, details are provided in the following Articles:
- Memory leak when a Progress Class implements a .NET interface
- Memory leak when using nested method calls.
For further information on the garbage collection of .Net Objects, review the following Articles which expand on the information above:
ABL Garbage Collection:
- Unlike .Net garbage collection, ABL Garbage Collection is performed synchronously in the same thread running the application.
- When there are no more references to an object in the session, then the ABL garbage collector removes the object (almost) immediately.
- The only specific place where ABL garbage collection is forced to happen is on return from an AppServer call (deactivate procedure). The product specification states:
"When an object's reference count goes to zero, it will be placed on a list of objects to garbage collect. The system will check for objects to garbage collect at regular intervals. The interval used and the order in which objects are destroyed is indeterminate. However, on an AppServer, garbage collection is guaranteed to run before the switch to a different connection context. This ensures that an object’s destructor will always run within the same connection context in which it was created."
For further discussion specific to ABL Garbage Collection, refer to Article:
To determine when an object is deleted by the Garbage Collector
Use -clientlog with -logginglevel set to 2 or above and -logentrytypes Dynobjects.* logging. For example:
prowin.exe -clientlog mylog.lg -logginglevel 2 -logentrytypes DB.Connects,4GLTrace,QryInfo,DynObjects.*,ProEvents.Other:4
4GLTrace and DynObjects.* client logging will write messages:
2 4GL DYNOBJECTS Deleted-by-GC Progress.Lang.Object Handle:16992 (Inic xpyfas @ 187) base_1
2 4GL DYNOBJECTS Deleted-by-GC .NET Object Handle:18576 (Inic xpyfas @ 208)
Dynobjects logging is useful to determine what is leaking:
A code example to walk the widget tree of dynamic objects that have been leaked by the session:
As an alternative to client logging, use the LOG-MANAGER system handle:
- This method requires predetermined code changes.
- While client log + dynobjects is useful when a session-wide trace log is required, this logging is switched on and off by statements compiled into the code and is therefore useful to narrow down code blocks in specific application areas:
LOG-MANAGER:LOG-ENTRY-TYPES = "DynObjects.*:4"
ABL Reference: Handle Attributes and Methods Reference - LOG-ENTRY-TYPES attribute
https://docs.progress.com/bundle/abl-reference/page/LOG-ENTRY-TYPES-attribute.html