Java mmap在Android上失败,“mmap failed:ENOMEM(Out of memory)”)

内存映射在 Android上的一个大文件在Java中工作得很好.但是当映射超过〜1.5GB时,即使使用多个映射调用,也会失败:
mmap failed: ENOMEM (Out of memory)

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

以下Java代码被称为几百次,每次调用请求〜1MB:

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

以避免请求一个大的连续的内存块,这常常难以被发现.请参阅完整的代码here.请记住,将“段大小”(即单个地图调用的大小)加倍没有任何影响,这意味着它将停留在类似的内存位置.同样重要的是要注意,两个略低于限制的应用程序都执行正常(暗示每个进程限制).

相关问题是here,here,here,here,here,here,here和here.

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

我已经读过这可能是虚拟地址空间的每个进程限制.在哪里可以找到更多关于这一点?我可以用NDK更改此设置吗?如何调用ulimit?可以madvise帮我一下吗

更新

有关可用于Java的mmap工具,请参阅我的答案here

解决方法

您的问题肯定是虚拟地址空间耗尽的原因.可能您的问题在32位Android设备上复制,用户地址空间可用于物理上限制为2GB,不能被碰撞. (虽然可能是3GB(不太可能),并且在OS构建过程中被配置).大概〜500 MB用于系统库,JVM及其堆.而且〜1.5 GB可供您使用.

在这种情况下,IMO的唯一方法是 – 不断映射到现在真正使用的文件段,并尽快取消映射未使用的文件.您可以使用某种滑动窗口,其中只有一小部分文件将映射到内存,并且完成后,取消映射该部分,提高您的窗口位置并映射更新的窗口,依此类推.

当您映射整个大文件时,您的进程也将成为系统内存不足的杀手的有吸引力的受害者.因为当您读取这样的映射文件时,物理内存的消耗会升高,有些时候进程会被杀死.

以上是来客网为你收集整理的Java mmap在Android上失败,“mmap failed:ENOMEM(Out of memory)”)全部内容,希望文章能够帮你解决Java mmap在Android上失败,“mmap failed:ENOMEM(Out of memory)”)所遇到的程序开发问题。

如果觉得来客网网站内容还不错,欢迎将来客网网站推荐给程序员好友。