代码之家  ›  专栏  ›  技术社区  ›  jumar

使用ByteBuffers和NIO时如何避免内存不足错误?

  •  3
  • jumar  · 技术社区  · 16 年前

    我在用 ByteBuffers FileChannels 将二进制数据写入文件。当对大文件或连续对多个文件执行此操作时,我会得到一个 OutOfMemoryError 例外。 我在其他地方读过 Bytebuffers NIO坏了,应该避免。你们中的任何一个都已经遇到过这样的问题,并找到了一个解决方案来高效地在Java文件中保存大量二进制数据吗?

    是JVM选项吗? -XX:MaxDirectMemorySize 怎么走?

    6 回复  |  直到 6 年前
        1
  •  6
  •   Tim Frey    16 年前

    我会说,不要创建一个包含所有数据的巨大的bytebuffer。创建一个小得多的bytebuffer,用数据填充它,然后将这些数据写入filechannel。然后重置bytebuffer并继续,直到写入所有数据。

        2
  •  4
  •   Stu Thompson Helter Scelter    16 年前

    检查Java的 Mapped Byte Buffers ,也称为“直接缓冲区”。基本上,这个机制使用操作系统的虚拟内存分页系统将缓冲区直接映射到磁盘。操作系统会神奇地、非常迅速地自动地将字节移动到磁盘和内存中,并且您不必担心更改虚拟机选项。这也将允许您利用Nio改进的性能优于传统的基于Java流的I/O,没有任何奇怪的黑客攻击。

    我能想到的只有两种捕获物:

    1. 在32位系统上,您被限制在4GB以下 所有映射字节缓冲区的总数 . (这实际上是我的应用程序的一个限制,现在我在64位体系结构上运行。)
    2. 实现是特定于JVM的,而不是需求。我用的是Sun的JVM,没有问题,但是YMMV。

    Kirk Pepperdine(一个有点著名的Java性能大师)涉及一个网站,www. javaPrimeCtutuung,它有更多的MB细节: NIO Performance Tips

        3
  •  1
  •   akash    6 年前

    如果您访问 随机时尚 (在这里读,跳过,在那里写,向后移动)然后你有问题;-)

    但是如果你只写大文件,你应该 认真地 考虑使用流。 java.io.FileOutputStream 可直接用于逐字节写入文件或包装在任何其他流中(即 DataOutputStream , ObjectOutputStream )为了方便写入浮点数、整数、字符串甚至可序列化对象。类似的类用于读取文件。

    流为您提供操作方便 (几乎)任意小内存中任意大的文件 . 在大多数情况下,它们是访问文件系统的首选方式。

        4
  •  0
  •   Cagatay    16 年前

    使用 transferFrom 方法应该有助于实现这一点,假设您以增量方式而不是像前面的答案所指出的那样一次性写入通道。

        5
  •  0
  •   Darron    16 年前

    这取决于特定的JDK供应商和版本。

    在一些Sun JVM中,GC中有一个bug。直接内存不足不会触发主堆中的GC,但直接内存由主堆中的垃圾直接字节缓冲区固定。如果主堆大部分是空的,那么它们在很长一段时间内不会被收集。

    即使您自己不使用直接缓冲区,这也可能会让您头疼,因为JVM可能会代表您创建直接缓冲区。例如,将非直接的bytebuffer写入socketchannel会在封面下创建一个直接缓冲区,用于实际的I/O操作。

    解决方法是自己使用少量的直接缓冲区,并保留它们以供重用。

        6
  •  0
  •   akash    6 年前

    前两种回答似乎很合理。至于命令行开关是否工作,这取决于内存使用达到限制的速度。如果您没有足够的RAM和虚拟内存,可用内存至少是可用内存的三倍,那么您需要使用给出的备选建议之一。