"Error during serialization" with API for Java and large matrix

5 次查看(过去 30 天)
Hi,
I'm using the MATLAB API for Java to factor large matrices. Within my Java code I start the MatlabEngine:
MatlabEngine eng = MatlabEngine.startMatlab();
Then I call the svd function and pass it a large 2D array of double values as input:
// 'a' is a large double[][]
Object[] results = eng.feval(3, "svd", a);
double[][] S = (double[][])results[1];
double[][] V = (double[][])results[2];
This works very nicely for sizes of the array 'a' up to around 23000x23000. However for larger matrices, the Matlab call throws an exception:
com.mathworks.engine.MatlabExecutionException: svd
at com.mathworks.engine.FutureResult.get(FutureResult.java:64)
at com.mathworks.engine.MatlabEngine.feval(MatlabEngine.java:464)
at sandbox.TestSvdEvd.main(TestSvdEvd.java:184)
Caused by: com.mathworks.mvm.exec.MvmException: Error during serialization
... 3 more
com.mathworks.mvm.exec.MvmException: Error during serialization
Matlab has no problem processing the same matrix in a standalone Matlab process. So I seem to be hitting some memory limit with the MATLAB API for Java, however there's plenty of RAM available to the JVM.
So I guess my question(s) is: am I doing something wrong with the Java API? Is there some way I can increase the memory available to the Matlab engine to avoid this exception?
  3 个评论
Nick Rowell
Nick Rowell 2019-1-8
Hi Jan, thanks for your reply. I set the Java heap space to 120Gb (-Xmx120g), which is easily enough to handle an array of this size. Indeed, I can factor the array in Java using JAMA linear algebra library, it just takes a very long time. It's only when I switch to using the MatlabEngine that this exception occurs, which leads me to think it's due to some restriction on the memory available to the Matlab process, or the serialisation layer which must transport the data from Java to Matlab and back.
Nick Rowell
Nick Rowell 2019-1-9
I've investigated this further and I think I know what's going on. If I try and send a simple float[] array to Matlab then this works up to an array size of 1,073,741,809 elements, after which I get this same 'Error during serialization'. The maximum allowed size of an array in Java is 2,147,483,645 elements (give or take a few, depending on the VM) which is too close to 1,073,741,809 * 2 = 2,147,483,618 to be a coincidence. So it appears that the array is getting serialized to a short[] array internally by the MatlabEngine, which is overflowing the array size limit and causing this exception.
A possible workaround is to send the data to Matlab in chunks, reconstruct it in the Matlab workspace, perform the computation, then retrieve the data to Java in chunks. For my original 2D arrays, this could be done by transferring one row at a time. If that works then I'll write it up as the answer/workaround for this question.

请先登录,再进行评论。

采纳的回答

Nick Rowell
Nick Rowell 2019-1-9
编辑:Nick Rowell 2019-1-9
After some reverse-engineering of the MatlabEngine I figured out the problem - it was caused by the MatlabEngine flattening my array and serializing it into a 1D array of shorts for transfer to the Matlab process. For a large input array this can cause the serialized array to be longer than the array size limit imposed by Java (around 2147483645 elements, or Integer.MAX_VALUE - 2). Arrays containing more than ~536870906 doubles or ~1073741809 floats will overflow that. There's no simple fix for this but I can work around it by transferring my data in chunks. In this particular application, where I'm handling large 2D arrays, this can be done by transferring one row at a time between Matlab and Java. Here's some Java code that does this:
// 'eng' is the MatlabEngine
// 'a' is a large nxn array of doubles, with n > 23170, which we want to factorise
// Simply doing:
// Object[] results = eng.feval(3, "svd", a);
// fails with an 'com.mathworks.mvm.exec.MvmException: Error during serialization'
// Transfer one row at a time to the Matlab workspace
for(int row = 0; row < n; row++) {
eng.putVariable("row_"+row, a[row]);
}
// Compile the individual rows into one matrix in the Matlab workspace,
// cleaning up as we go to preserve memory
StringBuilder build_a = new StringBuilder();
build_a.append("a = [ row_0 ");
StringBuilder clear_rows = new StringBuilder();
clear_rows.append("clear row_0 ");
for(int row = 1; row < n; row++) {
build_a.append("; row_"+row);
clear_rows.append(" row_"+row);
}
build_a.append(" ];");
clear_rows.append(";");
eng.eval(build_a.toString());
eng.eval(clear_rows.toString());
// Compute the matrix factorisation
eng.eval("[U, S, V] = svd(a);");
eng.eval("clear a;");
// Retrieve the matrix V one row at a time
double[][] V = new double[n][];
for(int row = 0; row < n; row++) {
// row+1 due to Matlab 1-based indexing
eng.eval("row = V(" + (row+1) + ",:);");
V[row] = (double[])eng.getVariable("row");
eng.eval("clear row;");
}
eng.eval("clear V;");
// Retrieve the matrix S one row at a time
double[][] S = new double[n][];
for(int row = 0; row < n; row++) {
// row+1 due to Matlab 1-based indexing
eng.eval("row = S(" + (row+1) + ",:);");
S[row] = (double[])eng.getVariable("row");
eng.eval("clear row;");
}
eng.eval("clear S;");

更多回答(0 个)

类别

Help CenterFile Exchange 中查找有关 Call MATLAB from Java 的更多信息

产品


版本

R2018b

Community Treasure Hunt

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

Start Hunting!

Translated by