[mapguide-internals] Memory leakage in WebTier (Java)

Walt Welton-Lair walt.welton-lair at autodesk.com
Thu Sep 2 18:35:28 EDT 2010


I think the fix is simply to update line 2003 in java.cxx with the following:

  Replaceall(tm, "new $javaclassname(cPtr, $owner)", "($javaclassname)ObjectFactory.createObject($module.getClassId(cPtr), cPtr, true)");

This is analogous to what's in csharp.cxx (see line 1829).

Walt

-----Original Message-----
From: Walt Welton-Lair 
Sent: Thursday, September 02, 2010 6:28 PM
To: 'MapGuide Internals Mail List'
Subject: RE: [mapguide-internals] Memory leakage in WebTier (Java)

We always want our Java (and .NET) proxy wrappers to "own" the wrapped C++ object, and "delete" it when the managed class is garbage collected.

In MapGuide, the meaning of "ownership" via the swigCMemOwn flag is slightly different than what's described in the SWIG manual.  Ownership in MG means that when the proxy wrapper is created, the ref count of the wrapped C++ class is incremented by one.  When the proxy class is GC'ed, the ref count of the C++ class *must* then be decremented again.  The finalizer doesn't explicitly delete the C++ object; it just calls IDisposable::Release.

In any case, we'll need to make a small update to the SWIG Java module (Oem\SWIGEx\source\Modules\java.cxx) to fix this.

Walt

-----Original Message-----
From: mapguide-internals-bounces at lists.osgeo.org [mailto:mapguide-internals-bounces at lists.osgeo.org] On Behalf Of Andreas Morf
Sent: Thursday, September 02, 2010 2:49 PM
To: 'MapGuide Internals Mail List'
Subject: RE: [mapguide-internals] Memory leakage in WebTier (Java)

Walt,
I'm aware of this since quite a while but according to SWIG manual
(http://www.swig.org/Doc1.3/Java.html#memory_management) this is default
behaviour/semantics of SWIG-Java. I thought that Mg-developers are aware of
this and continued investigating in C++ code...

This default behaviour may be overridden with a %newobject annotation at all
unmananged object delivery methods - silly queston of java programmer: how
to locate them?

Why does SWIG-C# handle this different (there is now equivalent swig-c# doc
about that aspect)?

Andreas

-----Ursprüngliche Nachricht-----
Von: mapguide-internals-bounces at lists.osgeo.org
[mailto:mapguide-internals-bounces at lists.osgeo.org] Im Auftrag von Walt
Welton-Lair
Gesendet: Donnerstag, 2. September 2010 19:54
An: MapGuide Internals Mail List
Betreff: RE: [mapguide-internals] Memory leakage in WebTier (Java)

swigCMemOwn=false is the problem....


Here's the implementation of MgByteSource.GetReader in the SWIG generated
.NET version of the API:

public MgByteReader GetReader()
{
    IntPtr cPtr = FoundationApiPINVOKE.MgByteSource_GetReader(swigCPtr);
    return (cPtr == IntPtr.Zero) ? null :
(MgByteReader)FoundationApiPINVOKE.createObject(FoundationApiPINVOKE.getClas
sId(cPtr), FoundationApiPINVOKE.getNameSpace(cPtr),
FoundationApiPINVOKE.getClassName(cPtr), cPtr, true);
}

Notice the last argument to FoundationApiPINVOKE.createObject is true - this
corresponds to the swigCMemOwn value.  When the MgByteReader is GC'ed, if
swigCMemOwn is true then the unmanaged C++ object is released:

~MgByteReader() {
    Dispose();
  }

public override void Dispose() {
    if(swigCPtr != IntPtr.Zero && swigCMemOwn) {
      swigCMemOwn = false;
      FoundationApiPINVOKE.delete_MgByteReader(swigCPtr);
    }
    swigCPtr = IntPtr.Zero;
    GC.SuppressFinalize(this);
    base.Dispose();
}

The call to FoundationApiPINVOKE.delete_MgByteReader is where the unmanaged
C++ reader is released.  (Note that once the last reference to the reader is
released it will also release its reference to the source object.)


Now look at the implementation of  MgByteSource.GetReader in Java:

public MgByteReader GetReader() throws MgException  {
    long cPtr = MapGuideJavaApiJNI.MgByteSource_GetReader(swigCPtr);
    return (cPtr == 0) ? null :
(MgByteReader)ObjectFactory.createObject(MapGuideJavaApiJNI.getClassId(cPtr)
, cPtr, false);
}

The last argument - which determines what swigCMemOwn gets set to - is
false.  Ooooops...

I did a search and all calls to ObjectFactory.createObject pass in false.
So *every* unmanaged object ends up getting leaked if you use the Java API.

Wow - that's a major bug.  Ooooops again...

Walt

-----Original Message-----
From: mapguide-internals-bounces at lists.osgeo.org
[mailto:mapguide-internals-bounces at lists.osgeo.org] On Behalf Of Andreas
Morf
Sent: Thursday, September 02, 2010 10:40 AM
To: 'MapGuide Internals Mail List'
Subject: RE: [mapguide-internals] Memory leakage in WebTier (Java)

Walt,
Indeed it doesn't - in both cases: the layerDefContent object is not owned
by java (ie. swigCMemOwn=false because it is provided by
C++ layer by ::GetReader) so just the java object is destroyed and no
delete-call is made to the C++ layer.
But even if the MgByteReader-C++ object would have been destroyed, I cannot
see (in the code) where the final reference to the 'src'
C++ object is released and 'src' is destroyed...

Andreas


> -----Original Message-----
> From: mapguide-internals-bounces at lists.osgeo.org
[mailto:mapguide-internals-bounces at lists.osgeo.org]
> On Behalf Of Walt Welton-Lair
> Sent: Thursday, September 02, 2010 4:06 PM
> To: MapGuide Internals Mail List
> Subject: RE: [mapguide-internals] Memory leakage in WebTier (Java)
> 
> Why should the GC order matter at all?
> 
> - case 1: src gets GC'ed first, followed by layerDefContent
>         When the src gets GC'ed the ref count of the associated C++ object
drops back to one - no C++
> objects are yet destroyed.  Then when the layerDefContent object gets
GC'ed the ref count for its C+
> object goes to zero and it gets destroyed, which in turn will release the
final reference to the src
> C++ object and it will also get destroyed.
> 
> - case 2: layerDefContent gets GC'ed first, followed by src
>         When the layerDefContent gets GC'ed the ref count for its C+
object goes to zero and it gets
> destroyed, and the ref count of the src C++ object drops back to one.
Then when the src object gets
> GC'ed the ref count for the src C+ object goes to zero and it also gets
destroyed.
> 
> 
> It seems like some of the managed objects are not getting GC'ed, which in
turn is causing the
> underlying C++ objects to not be destroyed.
> 
> Walt
> 

_______________________________________________
mapguide-internals mailing list
mapguide-internals at lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/mapguide-internals
_______________________________________________
mapguide-internals mailing list
mapguide-internals at lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/mapguide-internals

_______________________________________________
mapguide-internals mailing list
mapguide-internals at lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/mapguide-internals


More information about the mapguide-internals mailing list