4

我有一个函数可以解压缩Z使用 zlib 库(改编自此处)打包的字节数组。

  • 打包后的数据大小为 4.11 GB,解压后的数据为 6.65 GB。我有 32GB 的内存,所以这远低于限制。
  • 我尝试将 Java 堆大小增加到 15.96GB,但这并没有帮助。
  • MATLAB_JAVA 环境变量指向 jre1.8.0_144。

我得到了神秘的错误

'MATLAB array exceeds an internal Java limit.' 

在此代码的第 2

import com.mathworks.mlwidgets.io.InterruptibleStreamCopier
a=java.io.ByteArrayInputStream(Z);
b=java.util.zip.GZIPInputStream(a);
isc = InterruptibleStreamCopier.getInterruptibleStreamCopier;
c = java.io.ByteArrayOutputStream;
isc.copyStream(b,c);
M=typecast(c.toByteArray,'uint8');

尝试实施 Mark Adler 的建议:

Z=reshape(Z,[],8);
import com.mathworks.mlwidgets.io.InterruptibleStreamCopier
a=java.io.ByteArrayInputStream(Z(:,1));
b=java.util.zip.GZIPInputStream(a);
for ct = 2:8,b.read(Z(:,ct));end
isc = InterruptibleStreamCopier.getInterruptibleStreamCopier;
c = java.io.ByteArrayOutputStream;
isc.copyStream(b,c);

但在这isc.copystream我得到这个错误:

Java exception occurred:
java.io.EOFException: Unexpected end of ZLIB input stream

    at java.util.zip.InflaterInputStream.fill(Unknown Source)

    at java.util.zip.InflaterInputStream.read(Unknown Source)

    at java.util.zip.GZIPInputStream.read(Unknown Source)

    at java.io.FilterInputStream.read(Unknown Source)

    at com.mathworks.mlwidgets.io.InterruptibleStreamCopier.copyStream(InterruptibleStreamCopier.java:72)

    at com.mathworks.mlwidgets.io.InterruptibleStreamCopier.copyStream(InterruptibleStreamCopier.java:51)

直接从文件 中读取我试图直接从文件中读取数据。

streamCopier = com.mathworks.mlwidgets.io.InterruptibleStreamCopier.getInterruptibleStreamCopier;
fileInStream = java.io.FileInputStream(java.io.File(filename));
fileInStream.skip(datastart);
gzipInStream = java.util.zip.GZIPInputStream( fileInStream );
baos = java.io.ByteArrayOutputStream;
streamCopier.copyStream(gzipInStream,baos);
data = baos.toByteArray;
baos.close;
gzipInStream.close;
fileInStream.close;

适用于小文件,但对于大文件,我得到:

Java exception occurred:
java.lang.OutOfMemoryError

在线streamCopier.copyStream(gzipInStream,baos);

4

2 回答 2

6

瓶颈似乎是正在创建的每个单独 Java 对象的大小。发生这种情况是java.io.ByteArrayInputStream(Z)因为 MATLAB 数组无法在没有转换的情况下输入到 Java 中,并且在 中copyStream,数据实际上被复制到输出缓冲区/内存中。我有一个类似的想法,将对象拆分成允许大小(src)的块:

function chunkDunzip(Z)
%% Imports:
import com.mathworks.mlwidgets.io.InterruptibleStreamCopier
%% Definitions:
MAX_CHUNK = 100*1024*1024; % 100 MB, just an example
%% Split to chunks:
nChunks = ceil(numel(Z)/MAX_CHUNK);
chunkBounds = round(linspace(0, numel(Z), max(2,nChunks)) );

V = java.util.Vector();
for indC = 1:numel(chunkBounds)-1
  V.add(java.io.ByteArrayInputStream(Z(chunkBounds(indC)+1:chunkBounds(indC+1))));
end

S = java.io.SequenceInputStream(V.elements);  
b = java.util.zip.InflaterInputStream(S);

isc = InterruptibleStreamCopier.getInterruptibleStreamCopier;
c = java.io.FileOutputStream(java.io.File('D:\outFile.bin'));
isc.copyStream(b,c);
c.close();

end

几个注意事项:

  1. 我使用了 aFileOutputStream因为它没有遇到 Java 对象的内部限制(就我的测试而言)。
  2. 仍然需要增加 Java 堆内存。
  3. 我使用deflate演示了它,而不是 gzip。gzip 的解决方案非常相似——如果这是一个问题,我会修改它。
于 2017-10-19T17:03:22.567 回答
2

你不需要一口气读完。您可以重复b.read()调用,在其中提供某个规定长度的字节数组。重复直到它返回-1。使用生成的块在一个巨大的 MATLAB 数组中构建您的结果,而不是在一个巨大的 Java 数组中。

于 2017-10-15T15:29:36.620 回答