我的Java应用程序使用内存映射文件(MappedByteBuffer,FileChannel和RandomAccessFile)处理大型二进制数据文件。它通常需要增长二进制文件 - 我目前的方法是使用更大的区域重新映射文件。
它有效,但有两个问题
有哪些替代方法,最好的方法是什么?
此外,我无法弄清楚为什么会出现第二个问题。还请提出您对该问题的看法。
谢谢!
增长文件的当前代码,如果它有帮助:
(set! data (.map ^FileChannel data-fc FileChannel$MapMode/READ_WRITE
0 (+ (.limit ^MappedByteBuffer data) (+ DOC-HDR room))))
答案 0 :(得分:5)
您可能希望以更大的块增长文件。每次重新映射时使用加倍,例如dynamic array,这样增长的成本就是摊销常数。
我不知道为什么重新映射会在30,000次后挂起,这看起来很奇怪。但如果您使用我建议的方案,您应该可以使用 lot 少于30,000次重映射。
答案 1 :(得分:0)
即使您明确调用了清理程序,JVM也不会清除内存映射。感谢@EJP的纠正。
如果你创造了32,000个,那么它们可能同时存在。顺便说一句:我怀疑你可能达到了15位的限制。
唯一的解决方案是;不要创建这么多的映射。您可以使用小于4K的映射映射整个磁盘4 TB磁盘。
如果您知道使用量会增长,我不会创建小于16到128 MB的映射,我会考虑每个映射最多1 GB。您可以以较低的成本完成此操作的原因是,在您实际使用这些页面之前,不会分配主内存和磁盘空间。即主存储器使用量一次增长4 KB。
我不会创建2 GB映射的唯一原因是Java不支持这种情况,因为Integer.MAX_VALUE大小限制:(如果你有2 GB或更多,你必须创建多个映射。
答案 2 :(得分:0)
除非您能够承受文件的指数增长,例如倍增或任何其他常数乘数,否则您需要考虑是否真的需要MappedByteBuffer
,考虑到它们的局限性(无法增长文件,不能GC等)。我个人要么正在审查问题,要么在“rw”模式下使用RandomAccessFile
,可能在其顶部有一个虚拟阵列层。