java - 我应该如何在不溢出堆的情况下处理大型(70MB 未压缩)字节流的解压?

标签 java heap-memory gzipinputstream

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

在 C# 方面,一切正常,包括我们最大的测试文件(未压缩的 70MB),但是我们遇到了 Java 堆空间不足的问题。我们已尝试将堆大小增加到 IDE 的容量,但问题仍未解决。

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

编辑:根据@MarkoTopolnik 的建议修改以下代码。通过更改,崩溃前读取了 1700 万个字符。

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();
}

代码在 ArrayList 中超过 760 万个字符后终止,堆栈跟踪表明 ArrayList.add() 调用是原因(触发内部数组展开后失败)

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

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

最佳答案

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

关于java - 我应该如何在不溢出堆的情况下处理大型(70MB 未压缩)字节流的解压?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16843936/

相关文章:

java - 从 XML 或 Json 模式生成 Java 域类与手动编写 Java 类的优缺点

java - 如何组合列表中的其他项目来为列表元素中的项目创建子集?

c++ - 在C/C++中,链表只有头指针分配在栈中,其他节点分配在堆中。这可能会导致内存泄漏?

java - 如何使用 java 将八位字节流读取为纯字符串/文本?

java - 如何使用 GZIPInputStream 修复 EOF 读取错误

java - 连接在不活动时间后挂起

java - 在为 HashMap 分配值时使用(对象)

由于堆中存在大量 JSP/HTML 内容而导致 Java OutOfMemory

java - 堆栈帧大小是否有上限