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