Salesforce

If progress class implements dotnet interface, progress GC doesn't appear to collect it

« Go Back

Information

 
TitleIf progress class implements dotnet interface, progress GC doesn't appear to collect it
URL Name000028428
Article Number000148819
EnvironmentOpenEdge 10.2x
OpenEdge 11.x
Microsoft Windows
Question/Problem Description

If an ABL class implements a .NET interface, the .NET Garbage Collector doesn't appear collect it when it goes out of scope. 

Example:

/* test.p: */
RUN main-block.
RUN main-block.
RUN main-block.
RUN main-block.

MESSAGE 'done'
    VIEW-AS ALERT-BOX INFORMATION.

PROCEDURE main-block:
    DEFINE VARIABLE progObj AS ProgressSomeClass NO-UNDO.

    progObj = NEW ProgressSomeClass().
    MESSAGE 'done with one'
        VIEW-AS ALERT-BOX INFORMATION.
END PROCEDURE.

/* ProgressSomeClass.cls: */
USING Progress.Lang.*.

CLASS ProgressSomeClass IMPLEMENTS TestLib1.IDotNetSomeClass:

    METHOD PUBLIC VOID SomeMethod(  ):
    END METHOD.

    DESTRUCTOR PUBLIC ProgressSomeClass ( ):

        MESSAGE 'in progresssomeclass destructor'
            VIEW-AS ALERT-BOX INFORMATION.
       
    END DESTRUCTOR.
END CLASS.

/* Dotnet code: */
interface.cs:
namespace TestLib1
{
    public interface IDotNetSomeClass
    {
        void SomeMethod();
    }
}


Steps to Reproduce
Clarifying Information
Error Message
Defect Number
Enhancement Number
Cause

This is expected behavior.  There are essentially two garbage collectors at work when using hybrid objects.  This is because half the object exists in ABL memory and the other half exists on the .NET bridge.

When all references are removed for such an object .NET will eventually clean up that memory, which happens with a lower frequency when it doesn't have a great deal of work to do (i.e. small or few objects to cleanup), then the OpenEdge garbage collector waits until another interaction across the .NET bridge before checking on whether objects were cleaned up on the .NET side.

The ABL process has no control over when the .NET Garbage Collector does its work.  This uses a heuristic algorithm for deciding when it runs.

Resolution

When you are aware that objects have gone out of scope, the only way to ensure that the OpenEdge garbage collector goes to work is to fire a method or perform some sort of other interaction with the bridge, such as creating an object.  Otherwise you can manually fire the garbage collector, which causes OpenEdge to check the bridge earlier and run its own garbage collection.  

To do this you would want to make a multiple pass call in order to ensure that objects that need cleaning are indeed cleaned up.  The below code should accomplish this task:

System.GC:Collect().
System.GC:WaitForPendingFinalizers().
System.GC:Collect().

Workaround
Notes

It is generally considered a bad idea to manually call System.GC:Collect() directly.  The logic behind the design of this algorithm, in .NET, is to avoid perceptible performance impact and calling it directly can inhibit performance by causing the collector to check the reference count of every single instantiated object, rather than working on a just in time (JIT) basis.

Keyword Phrase
Last Modified Date9/13/2015 5:31 AM

Powered by