Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在不溢出堆的情况下处理大字节流(70MB未压缩)的解压缩?_Java_Heap Memory_Gzipinputstream - Fatal编程技术网

Java 如何在不溢出堆的情况下处理大字节流(70MB未压缩)的解压缩?

Java 如何在不溢出堆的情况下处理大字节流(70MB未压缩)的解压缩?,java,heap-memory,gzipinputstream,Java,Heap Memory,Gzipinputstream,我正在为一些系统之间的交互实现GZIP压缩。这些系统都是用Java和C#编写的,因此GZIP流在两侧都使用,因为它们具有标准库支持 在C#端,所有东西都可以运行,包括我们最大的测试文件(70MB未压缩),但是我们遇到了Java堆空间不足的问题。我们已经尝试将堆大小增加到IDE的容量,但问题仍然没有解决 我已经采取了一些步骤来尝试和优化Java代码,但似乎没有什么能阻止数据堆积在堆中。有什么好办法处理这个问题吗?下面是我当前(处理较小流)解决方案的子集 编辑:使用@MarkoTopolnik的建议

我正在为一些系统之间的交互实现GZIP压缩。这些系统都是用Java和C#编写的,因此GZIP流在两侧都使用,因为它们具有标准库支持

在C#端,所有东西都可以运行,包括我们最大的测试文件(70MB未压缩),但是我们遇到了Java堆空间不足的问题。我们已经尝试将堆大小增加到IDE的容量,但问题仍然没有解决

我已经采取了一些步骤来尝试和优化Java代码,但似乎没有什么能阻止数据堆积在堆中。有什么好办法处理这个问题吗?下面是我当前(处理较小流)解决方案的子集

编辑:使用@MarkoTopolnik的建议修改以下代码。经过更改,崩溃前将读取1700万个字符

公共静态字符串解压缩(字节[]压缩,整数大小)
{
GZIPInputStream解压器;
缓冲读取器;
字符buf[]=新字符[(大小<2048)?大小:2048];
Writer ret=新StringWriter(基本长度);
解压缩器=新的GZIPInputStream(新的ByteArrayInputStream(已压缩),buf.length);
reader=新的BufferedReader(新的InputStreamReader(解压器,“UTF-8”));
int charsRead;
while((charsRead=reader.read(buf,0,buf.length))!=-1)
{
ret.write(buf,0,charsRead);
}
解压器关闭();
reader.close();
返回ret.toString();
}
代码在
ArrayList
中命中略多于760万个字符后死亡,堆栈跟踪表明
ArrayList.add()
调用是原因(触发要扩展的内部数组后失败)

对于上面编辑的代码,调用
AbstractStringBuilder.expandCapacity()
会终止程序


是否有一种内存开销较低的方法来实现动态数组,或者可以使用某种完全不同的方法从解压缩流中获取字符串?如有任何建议,将不胜感激

我宁愿将其分块,而不是将整个内容读入内存:一次读入1024字节的缓冲区,然后立即将其写出来,更像是一个Unix管道,而不是两步读/写过程。

哦,是的,有更有效的方法。代码中最明显的低效是创建了
ArrayList
。这意味着每个字符占用大约30字节的内存。乘以你的760万,就是250MB


您必须使用的是
StringWriter
及其方法
write(char[],int,int)
,您可以使用现有的相同缓冲区调用该方法。这将提高大约25倍的内存效率。

由于现有的框架限制,这通常不是一个选项。我想说OP就是这样一个例子。是的,我看不到用我们现有的框架实现这一点的方法。函数必须返回字符串,并且必须压缩给定的字节数组。有了这些限制,我看不到一种实现你的解决方案的方法(如果我错了,请纠正我)。听起来你是对的。我建议在安装了所有插件的情况下使用VisualVM来查看内存的消耗情况。也许是时候抛弃你的框架了。谢谢你!在超出堆之前,我又获得了1000万个字符。这并不能完全解决问题,但有一个良好的开端。这一点令人惊讶。我想这是因为我没有考虑
字符
缓存。
public static String decompress(byte[] compressed, int size)
{
    GZIPInputStream decompresser;
    BufferedReader reader;
    char buf[] = new char[(size < 2048) ? size : 2048];
    Writer ret = new StringWriter( buf.length );

    decompresser = new GZIPInputStream( new ByteArrayInputStream( compressed ), buf.length );
    reader = new BufferedReader( new InputStreamReader( decompresser, "UTF-8" ) );

    int charsRead;
    while( (charsRead = reader.read( buf, 0, buf.length )) != -1 )
    {
        ret.write( buf, 0, charsRead );
    }
    decompresser.close();
    reader.close();

    return ret.toString();
}