Is there a memory leak when working with MWStructArrays in MATLAB Builder JA and/or how should I work with these?

4 views (last 30 days)
When I create a number of MWStructArrays memory appears to keep increasing. Even if I dispose of the structs in between. The following example illustrates this:
 
package com.test.matlab;
import com.mathworks.toolbox.javabuilder.MWArray;
import com.mathworks.toolbox.javabuilder.MWNumericArray;
public class MatlabMemoryLeakClient {
public static void main(String[] args) {
try {
// Just to load javabuilder.jar so we know how much memory it uses
MWNumericArray init = new MWNumericArray(0);
MWArray.disposeArray(init);
System.out.println("Press ENTER when ready to go...");
// Wait for user to press enter
System.in.read();
for (int i=0; i < 5000; i++) {
final String[] FIELDS = new String[]{"Field1", "Field2", "Field3", "Field4"};
final int KMAX = 200;
MWStructArray data5 = new MWStructArray(1, KMAX, FIELDS);
for (int k=0; k < KMAX; k++) {
data5.set(FIELDS[0], k+1, new MWNumericArray(k*1.13));
data5.set(FIELDS[1], k+1, new MWNumericArray(k*9.48));
data5.set(FIELDS[2], k+1, new MWCharArray("TEST1" + k*9.48));
data5.set(FIELDS[3], k+1, new MWCharArray("TEST2" + k*9.48));
}
MWArray.disposeArray(data5);
System.out.println("MWStructArray. Run=<" + i + ">");
}
Thread.sleep(10 * 60 * 1000);
} catch (Throwable e) {
System.out.println("Error in matlab testing. Exception=<" + e);
}
}
}

Accepted Answer

MathWorks Support Team
MathWorks Support Team on 11 Dec 2013
The problem here is with the anonymous MWArrays which you are creating to fill the struct array with. We will try to explain this graphically, but for this we slightly simplify the example: we use only one field: "Field1" and set KMAX = 1.
 
You start with creating the MWStructArray:
 
MWStructArray data5 = new MWStructArray(1, KMAX, FIELDS);
You then call:
 
data5.set(FIELDS[0], k + 1, new MWNumericArray(k * 1.13));
 
Where the new MWNumericArray(k * 1.13) part creates a new anonymous MWNumericArray with an underlying native MATLAB array with the actual data:
And the set operation makes, in accordance to the documentation "If element is of type MWArray, the cell at index set to a shared copy of the underlying MATLAB array", Field1 point to the underlying native MATLAB array:
 
Then when your code continues, the anonymous array goes out of scope. However in Java going out of scope means that it gets marked for being disposed, it does not necessarily mean that the object is really deleted at that time; Java itself determines whether and when to run the object's finalizer.
 
It is important to note here that the Java Garbage Collector is not aware of the size of the Native MATLAB array to which the anonymous MWNumericArray is keeping a reference; it only sees the relatively small Java part of the MWNumericArray. This could lead to the Garbage Collector deciding to never release the anonymous MWNumericArray at all (i.e. it does not think it is worth the CPU cycles to clear the array which is using only a little amount of memory anyway).
 
So you will have a situation:
Then when you do specifically dispose of the MWStructArray with MWarray.disposeArray, data5 is really deleted and not only marked for deletion. This will also delete Field1 and its reference to the Native MATLAB Array, leaving:
But as you can see the anonymous MWNumericArray may still exist and if so, it does still have a reference to the Native MATLAB Array and as long as this is true, the Native MATLAB Array may not be deleted. This may lead to something which looks like a memory leak, but in fact it is not, it is how finalizers and garbage collection work in Java in combination with how MWArrays may have large underlying native data.
 
Now how to prevent this from happening?
 
There are two options:
 
Instead of using an anonymous array you can use a temporary named variable which you can specifically dispose:
 
MWNumericArray temp = new MWNumericArray(k * 1.13);
data5.set(FIELDS[0], k + 1, temp);
MWArray.disposeArray(temp);
 
The following illustrations show what happens in this situation:
MWNumericArray temp = new MWNumericArray(k * 1.13);
data5.set(FIELDS[0], k + 1, temp);
MWArray.disposeArray(temp);
If you then also call MWArray.disposeArray(data5); all references to the native MATLAB array are removed and then the native array will also be cleared immediately.
 
Or even easier: the set method directly accepts native Java datatypes:
 
data5.set(FIELDS[0], k + 1, k*1.13);
 
Which would basically directly create:
 
Where again MWArray.disposeArray(data5); would remove all references to the native array and clear it.

More Answers (0)

Categories

Find more on Java Package Integration in Help Center and File Exchange

Tags

No tags entered yet.

Products


Release

R2009b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!