我在用着 ByteBuffersFileChannels 将二进制数据写入文件。当对大文件或连续对多个文件执行此操作时,我得到一个 OutOfMemoryError 例外。我在其他地方读过使用 Bytebuffers NIO 已损坏,应避免使用。你们中是否有人已经遇到过此类问题并找到了一种解决方案来有效地将大量二进制数据保存在java文件中?

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

有帮助吗?

解决方案

我想说不要创建一个包含所有数据的巨大 ByteBuffer。创建一个更小的 ByteBuffer,用数据填充它,然后将这些数据写入 FileChannel。然后重置ByteBuffer并继续,直到所有数据被写入。

其他提示

查看 Java 的 映射字节缓冲区, ,也称为“直接缓冲区”。基本上,这种机制使用操作系统的虚拟内存分页系统将缓冲区直接“映射”到磁盘。操作系统将自动、快速地管理将字节移入/移出磁盘和内存,并且您不必担心更改虚拟机选项。这还将使您能够利用 NIO 相对于传统的基于 java 流的 I/O 的改进性能,而无需任何奇怪的修改。

我能想到的唯一两个问题是:

  1. 在 32 位系统上,您的空间限制为不到 4GB 所有映射字节缓冲区的总计. 。(这实际上是我的应用程序的限制,我现在在 64 位架构上运行。)
  2. 实现是 JVM 特定的,不是必需的。我用的是Sun的JVM,没有问题,但是YMMV。

Kirk Pepperdine(一位颇有名气的 Java 性能专家)参与了一个网站 www.JavaPerformanceTuning.com,该网站提供了更多 MBB 详细信息: NIO 性能技巧

如果您访问 a 中的文件 随机时尚 (在这里读,跳过,在那里写,向后移动)那么你就有问题了;-)

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

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

使用 从转移 方法应该对此有所帮助,假设您增量地写入通道,而不是像之前的答案也指出的那样一次全部写入。

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

某些 Sun JVM 中的 GC 存在错误。直接内存不足不会触发主堆中的 GC,但直接内存会被主堆中的垃圾直接 ByteBuffer 所固定。如果主堆大部分是空的,那么它们很长时间都不会被收集。

即使您自己没有使用直接缓冲区,这也会让您感到烦恼,因为 JVM 可能会代表您创建直接缓冲区。例如,将非直接 ByteBuffer 写入 SocketChannel 会在幕后创建一个直接缓冲区以用于实际的 I/O 操作。

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

前面两个回答看起来很有道理。至于命令行开关是否起作用,取决于你的内存使用达到极限的速度。如果您没有足够的可用内存和虚拟内存来至少使可用内存增加三倍,那么您将需要使用给出的替代建议之一。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top