<br><tt><font size=2>Hi</font></tt>
<br>
<br><tt><font size=2>> I don't totally understand how all of the SWIG
stuff works, but I can follow<br>
> it a bit.  The source for this is:<br>
It's easier to watch the SWIG-generated JNI-Code in mapscript/java/mapscript_wrap.c
</font></tt>
<br><tt><font size=2>Example: </font></tt>
<br><tt><font size=2>  mapscriptJNI.delete_imageObj(swigCPtr);</font></tt>
<br><tt><font size=2>is implemented by the C-function</font></tt>
<br><tt><font size=2>  SWIGEXPORT jbyteArray JNICALL Java_edu_umn_gis_mapscript_mapscriptJNI_imageObj_1getBytes
</font></tt>
<br>
<br><tt><font size=2>> confirm that the caller must free the returned
array (with gdFree()).<br>
At the end of the long-named C-function you'll find a call to gdFree</font></tt>
<br>
<br><tt><font size=2>Can you estimate how much memory is lost in each step
of your</font></tt>
<br><tt><font size=2>testprogram? Is it approx. the size of the image?</font></tt>
<br>
<br><tt><font size=2>Benedikt Rothe</font></tt>
<br>
<br>
<br><tt><font size=2>mapserver-users-bounces@lists.osgeo.org schrieb am
21.02.2008 03:31:09:<br>
<br>
> <br>
> <br>
> rich.fromm wrote:<br>
> > <br>
> > Other than calling delete() on every mapserver object as applicable,
is<br>
> > there<br>
> > anything else that I can be doing?  I fear that there may
be a real<br>
> > genuine<br>
> > leak within mapserver, and that that might be hard to track down.<br>
> > <br>
> <br>
> I have narrowed this down to a smaller testcase, that only has two
mapscript<br>
> objects.<br>
> <br>
> I have a fixed map file, and I'm doing barely anything, just creating
the<br>
> map<br>
> object from the map file, drawing to the image object, and getting
the<br>
> bytes.<br>
> I am calling both map.delete() and img.delete() at the end.  Then
I loop<br>
> over<br>
> all of this repeatedly.<br>
> <br>
> This is a little bit of a simplification, but essentially what I'm
doing is<br>
> this:<br>
> <br>
>       for (int i = 0; i < loop; i++) {<br>
>          mapObj map = null;<br>
>          imageObj img = null;<br>
> <br>
>          try {<br>
>             map = new mapObj(filename);<br>
>             img = map.draw();<br>
>             byte[] bytes = img.getBytes();<br>
>          } catch (Exception e) {<br>
>             System.err.println("Caught
exception: " + e);<br>
>             e.printStackTrace(System.err);<br>
>          } finally {<br>
>             if (img != null) {<br>
>                img.delete();<br>
>             }<br>
>             if (map != null) {<br>
>                map.delete();<br>
>             }<br>
>          }<br>
>          System.gc();<br>
>       } // end for<br>
> <br>
> I have tried a number of variants of this (including outputting the
bytes to<br>
> a<br>
> file), and the offending line seems to be the call to imageObj.getBytes().<br>
> With it, my program leaks.  Without it, it does not:<br>
> <br>
> [rich@peyote mapserver_test 17:53:31]$ <mapserver_test> diff
-u<br>
> java/src/TestMapscript.java.bak1 java/src/TestMapscript.java.bak3<br>
> --- java/src/TestMapscript.java.bak1   2008-02-20 17:37:43.000000000
-0800<br>
> +++ java/src/TestMapscript.java.bak3   2008-02-20 17:53:27.000000000
-0800<br>
> @@ -1,4 +1,4 @@<br>
> -// this code does NOT leak<br>
> +// this code DOES leak<br>
>  <br>
>  import edu.umn.gis.mapscript.mapObj;<br>
>  import edu.umn.gis.mapscript.imageObj;<br>
> @@ -47,7 +47,7 @@<br>
>              System.err.println("Drawing
map to image object");<br>
>              img = map.draw();<br>
>  <br>
> -//             byte[] bytes = img.getBytes();<br>
> +            byte[] bytes = img.getBytes();<br>
>  //             int width = img.getWidth();<br>
>  //             int height = img.getHeight();<br>
>  //             System.err.println("The
image is of size " + width + " x " +<br>
> height + " and contains " + bytes.length + " bytes");<br>
> [rich@peyote mapserver_test 17:53:53]$ <mapserver_test> <br>
> <br>
> I am calling System.gc() at the end of each iteration.  And by
examining the<br>
> memory from java's perspective (Runtime.getRuntime().freeMemory()
and<br>
> Runtime.getRuntime().totalMemory()) I can see that it is reasonably
stable.<br>
> However, the memory as reported by top gradually grows.<br>
> <br>
> The source for imageObj.getBytes() is as follows:<br>
> <br>
> mapscript/java/edu/umn/gis/mapscript/imageObj.java<br>
> <br>
>   public byte[] getBytes() {<br>
>     return mapscriptJNI.imageObj_getBytes(swigCPtr);<br>
>   }<br>
> <br>
> I don't totally understand how all of the SWIG stuff works, but I
can follow<br>
> it a bit.  The source for this is:<br>
> <br>
>   getBytes() (mapscript/swiginc/image.i)<br>
> <br>
> which notes the following:<br>
> <br>
>     /*<br>
>    <br>
> -------------------------------------------------------------------------<br>
>     getBytes returns a gdBuffer structure (defined in mapscript.i)
which<br>
> must<br>
>     be typemapped to an object appropriate to the target
language.  This<br>
>     typemap must also gdFree the data member of the gdBuffer.
 See the type-<br>
>     maps in java/javamodule.i and python/pymodule.i for
examples.<br>
> <br>
>     contributed by Jerry Pisk, jerry.pisk@gmail.com<br>
>    <br>
> -------------------------------------------------------------------------<br>
>     */<br>
> <br>
> And all of the following:<br>
> <br>
>   msSaveImageBuffer() (maputil.c)<br>
>   msSaveImageBufferAGG() (mapagg.cpp)<br>
>   msSaveImageBufferGD() (mapgd.c)<br>
> <br>
> confirm that the caller must free the returned array (with gdFree()).<br>
> <br>
> What's not entirely clear to me is whether "the caller"
means the java<br>
> mapscript code, or the application writer.  In other words, am
I responsible<br>
> for doing this, or should this happen when I call img.delete() ?  Here
is<br>
> the<br>
> code for imageObj.delete():<br>
> <br>
> mapscript/java/edu/umn/gis/mapscript/imageObj.java<br>
> <br>
>   public void delete() {<br>
>     if(swigCPtr != 0 && swigCMemOwn) {<br>
>       swigCMemOwn = false;<br>
>       mapscriptJNI.delete_imageObj(swigCPtr);<br>
>     }<br>
>     swigCPtr = 0;<br>
>   }<br>
> <br>
> But even though I don't see a call to gdFree() there, it's not clear
to me<br>
> that it's not happening somewhere.  I don't understand the SWIG
path enough,<br>
> and I haven't yet tried following it in gdb.  (Although that
might be worth<br>
> trying.)<br>
> <br>
> If I am responsible for doing this, how do I do it?  It appears
to me that<br>
> gdFree() is not part of the mapscript API (it doesn't appear in the
docs),<br>
> and<br>
> just that it is just a mapscript internal function.<br>
> <br>
> Right now my test case is using a fairly complicated mapfile from
a large<br>
> data<br>
> source located in a postgis database.  I will try to see if I
can replicate<br>
> this problem with a simpler map file and/or synthetic data.<br>
> <br>
> But in the mean time I wanted to post this in case anyone might have
some<br>
> advice based on these observations.<br>
> <br>
> Once again, thanks for any help that anyone might be able to provide.<br>
> <br>
> - Rich<br>
> <br>
> p.s. This is all based on mapserver 5.0.0<br>
> <br>
> -- <br>
> View this message in context: http://www.nabble.com/thread-safety-<br>
> tp15514019p15603603.html<br>
> Sent from the Mapserver - User mailing list archive at Nabble.com.<br>
> <br>
> _______________________________________________<br>
> mapserver-users mailing list<br>
> mapserver-users@lists.osgeo.org<br>
> http://lists.osgeo.org/mailman/listinfo/mapserver-users<br>
</font></tt>