Java mmap在Android上失败,“mmap failed:ENOMEM(内存不足)”

内存映射在Java中的Android上的大文件效果很好。 但是,即使有多个映射调用,总映射超过〜1.5GB时也会失败:

mmap failed: ENOMEM (Out of memory) 

请参阅此处的完整讨论。 注意:它不会在服务器Linux上失败。 为应用程序启用了android:largeHeap =“true”。

下面的Java代码被称为几百次请求每个电话约1MB:

 ByteBuffer buf = raFile.getChannel().map(allowWrites ? FileChannel.MapMode.READ_WRITE : FileChannel.MapMode.READ_ONLY, offset, byteCount); 

以避免请求经常难以find的大的连续内存块。 在这里看到完整的代码。 请记住,“分段大小”(即单个地图调用的大小)加倍无效,这意味着它停止在相似的内存位置。 此外,重要的是要注意,两个应用程序都略低于限制执行罚款(提示每个进程的限制)。

相关的问题在这里 , 在 这里 , 在 这里 , 在这里 , 在 这里 , 在这里 , 在这里和这里 。

将使用多个文件,而不是一个文件与多个映射帮助?

我读过这可能是虚拟地址空间的每个进程限制。 我在哪里可以find更多关于这个? 我可以用NDK更改这个设置,例如如何调用ulimit ? 难道madvise能帮我一下吗?

更新

在这里查看我的答案,了解可用于Java的mmap工具

Solutions Collecting From Web of "Java mmap在Android上失败,“mmap failed:ENOMEM(内存不足)”"

你的问题肯定是由虚拟地址空间耗尽造成的。 可能你的问题在32位Android设备上重现,如果可用的用户地址空间是物理限制为2GB,并且不能被碰撞。 (虽然它可能是3GB(不太可能),并在操作系统构build过程中configuration)。 可能~500 MB用于系统库,JVM及其堆。 约1.5 GB可供您使用。

在这种情况下IMO的唯一方法 – 只保留现在真正使用的文件部分,并尽快取消映射未使用的文件部分。 你可以使用某种滑动窗口,只有一小部分文件将被映射到内存,当你完成 – 取消映射那个部分,提前你的窗口位置和映射那个更新的窗口,等等。

同样,当你映射整个大文件时,你的过程成为系统内存不足杀手的吸引力受害者。 因为当你阅读这样的映射文件时 – 物理内存的消耗会上升,并且在某个时刻进程将被终止。

由于我们不能通过API(不需要root访问)来增加Android上的虚拟地址限制,我还没有在Android源代码中看到这个。 我看到的唯一可能的解决scheme是实现一种caching,如果已经映射了一定数量的段,则访问这些caching并释放较旧的段。 这意味着我们正在自动执行操作系统通常为我们做的工作,这有点难看。

为了使它在Android下工作,可以使用这个答案/ util-mmap 。 希望有人可以在某些时候为Android实现这样的mmapcaching,也许甚至是我们:)

尝试在清单中添加largeHeap。 可能是有效的