【问题标题】:Memory required by JVM for creating CSV files and zip it on the flyJVM 创建 CSV 文件并即时压缩所需的内存
【发布时间】:2026-02-05 12:55:01
【问题描述】:

我正在使用字符串缓冲区和字节数组创建两个 CSV 文件。
我使用 ZipOutputStream 来生成 zip 文件。每个 csv 文件将有 14 列的 20K 记录。实际上,记录是从数据库中获取并存储在ArrayList 中的。我必须迭代列表并构建 StringBuffer 并将 StringBuffer 转换为字节数组以将其写入 zip 条目。

我想知道 JVM 需要的内存来完成从将记录存储在ArrayList 中开始的整个过程。
我在下面提供了代码 sn-p。

StringBuffer responseBuffer = new StringBuffer();
    String response = new String();
    response = "Hello, sdksad, sfksdfjk, World, Date, ask, askdl, sdkldfkl, skldkl, sdfklklgf, sdlksldklk, dfkjsk, dsfjksj, dsjfkj, sdfjkdsfj\n";
    for(int i=0;i<20000;i++){
        responseBuffer.append(response);
    }
    response = responseBuffer.toString();
    byte[] responseArray = response.getBytes();
    res.setContentType("application/zip");
    ZipOutputStream zout = new ZipOutputStream(res.getOutputStream());
    ZipEntry parentEntry = new ZipEntry("parent.csv");
    zout.putNextEntry(parentEntry);
    zout.write(responseArray);
    zout.closeEntry();
    ZipEntry childEntry = new ZipEntry("child.csv");
    zout.putNextEntry(childEntry);
    zout.write(responseArray);
    zout.closeEntry();
    zout.close();

请帮我解决这个问题。提前致谢。

【问题讨论】:

  • 您在执行此操作时遇到OutOfMemoryError 吗?
  • 将其增加到一个巨大的数字,然后运行应用程序并准确监控分配的内容
  • 该应用程序将被多个用户使用。当多个用户访问该应用程序时,我期待 OutOfMemoryError。所以我想知道每个用户的大约内存使用量。
  • @RumeshKumar 使用分析器。

标签: java object memory-management csv


【解决方案1】:

我猜您已经尝试计算将分配给 StringBuffer 和字节数组的字节数。但问题是您无法真正知道您的应用程序将使用多少内存,除非您对 CSV 记录的大小有上限。如果你希望你的软件稳定、健壮和可扩展,恐怕你问错了问题:你应该努力使用固定数量的内存来执行你需要完成的任务,在你的情况下似乎很容易。

关键是,在您的情况下,处理完全是 FIFO - 您从数据库中读取记录,然后将它们(以相同的顺序)写入 FIFO 流(在这种情况下为OutputStream)。甚至 zip 压缩也是基于流的,并且在内部使用固定数量的内存,因此您在那里完全安全。

而不是将整个输入缓冲在一个巨大的字符串中,然后将其转换为一个巨大的字节数组,然后将其写入输出流 - 您应该从数据库中单独读取每个响应元素(或固定大小的块,例如 100一次记录),并将其写入输出流。类似的东西

res.setContentType("application/zip");
ZipOutputStream zout = new ZipOutputStream(res.getOutputStream());
ZipEntry parentEntry = new ZipEntry("parent.csv");
zout.putNextEntry(parentEntry);
while (... fetch entries ...)
    zout.write(...data...)
zout.closeEntry();

这种方法的优势在于,由于它适用于小块,您可以轻松估计它们的大小,并为您的 JVM 分配足够的内存,使其永远不会崩溃。而且您知道,如果您的 CSV 文件将来超过 20K 行,它仍然可以工作。

【讨论】:

    【解决方案2】:

    要分析内存使用情况,您可以使用 Profiler

    JProfilerYourKit 非常擅长此操作。

    VisualVM在某种程度上也不错。

    【讨论】:

      【解决方案3】:

      您可以使用MemoryTestbench 测量内存。

      http://www.javaspecialists.eu/archive/Issue029.html

      这篇文章描述了该怎么做。它简单,精确到 1 个字节,我经常使用它。
      它甚至可以从 junit 测试用例中运行,所以它非常有用,而无法运行探查器 来自一个 junit 测试用例。

      使用该方法,您甚至可以测量一个 Integer 对象的内存大小。

      但是使用 zip 有一件特别的事情。 Zipstream 使用本机 c 库,在这种情况下,MemoryTestbench 可能无法测量该内存,仅测量 java 部分。
      您应该尝试两种变体,即 MemroyTestbench,并使用分析器 (jprof)。

      【讨论】: