【问题标题】:writing a huge file and Java heap space编写一个巨大的文件和 Java 堆空间
【发布时间】:2014-06-15 07:48:22
【问题描述】:

我正在尝试将 500mb 到 1.5gb 之间的大文件写入磁盘。 我用zipOutputStream 压缩然后通过网络发送

但在客户端,当我试图解压缩和 写吧,它给了我Java heap space.异常

  try (FileOutputStream fos = new FileOutputStream(outFile)) {
                int fileLength = (int)zipEntry.getSize();

                byte[] fileByte = new byte[fileLength];
                zips.read(fileByte);
                fos.write(fileByte);
            }

我知道为一个字节数组分配相当大的内存,但我怎么可能修复它?

【问题讨论】:

  • 您可以一次读取/写入文件的一部分。这就是 Stream 的设计用途。你一次读/写 8K 怎么样?
  • @PeterLawrey 如何为流分配大小?
  • 你也可以用Files.copy(zips, outFile.toPath());完成同样的事情。见here
  • @VGR 想让它成为一个答案吗?

标签: java file exception client-server


【解决方案1】:

您正在制作的byte[] 数组是您的缓冲区,缓冲区在从您的InputStream 传输到您的OutputStream 时用作堆中的临时位置。除非您希望您的程序在内存中使用 500mb - 1.5gb,否则您需要减少缓冲区大小。这是我用于执行此操作的常用方法。此方法使用 1kb 缓冲区,您可以玩一下大小,看看哪种最适合您。

/**
 * writes all bytes from inputStream to outputStream
 * @param source
 * @param destination
 * @throws IOException
 */
public static void pipeStreams(java.io.InputStream source, java.io.OutputStream destination) throws IOException {

    // 1kb buffer
    byte [] buffer = new byte[1024];
    int read = 0;
    while((read=source.read(buffer)) != -1) {
        destination.write(buffer, 0, read);
    }
    destination.flush();
}

您使用此方法的代码看起来像

try (FileOutputStream fos = new FileOutputStream(outFile)) {
    pipeStreams(zips, fos);
}

【讨论】:

  • 这工作了一周,传输文件将近 2 分钟,我被困在如何使它只读几个 KB 的部分,在这里你向我展示了。谢谢
  • 但是,我想知道缓冲区大小,例如10KB,是否意味着速度是10X?
  • 哦,我的错字,我的意思是速度
  • 我知道答案是否定的,但是,在这种情况下,我们如何定义一个使用最大可能空间进行缓冲的缓冲区,而不是小的 1KB 缓冲区?
  • @lonesome 瓶颈很可能是您的下载速度。只有当您看到高 CPU 利用率(忽略系统时间)时,才表明更大的缓冲区可能会有所帮助,顺便说一句,您自己尝试这样做并没有什么坏处。尝试 4 KB、16 KB、64 KB 等,看看您是否认为它会有所作为。
【解决方案2】:

您可以使用Files.copy(zips, outFile.toPath()); 完成相同的操作,而不是一次将整个文件读入内存。 Files.copy 方法的文档是here

【讨论】:

  • 那么,你认为哪种方式更好?缓冲还是这种复制方法?
  • Files.copy 更好,因为使用它的可读性更高,而且我相信它目前有自己的缓冲,所以它肯定不会比自己做的更糟糕。
  • 我使用 Files.copy 的堆空间仍然不足...有没有办法使用这个来指定缓冲区大小?
  • @Rimer 我需要查看您的代码。除非您尝试将整个文件读入 ByteArrayOutputStream 或其他内容,否则应该不可能耗尽空间。我知道我已经使用 Files.copy 复制了 3 GB 的文件,没有任何问题。
  • 我的错误是当我用完堆空间时运行了错误的代码分支。 Files.copy 成功了!它使用了一个 8KB 缓冲区,顺便说一句,我从源探听中发现...
猜你喜欢
  • 2012-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多