Kar*_*ell 10 java android memory-management mmap android-ndk
使用Java在Android上映射大型文件的内存效果很好.但是,即使有多个映射调用,当总共映射超过~1.5GB时,它也会失败:
mmap failed: ENOMEM (Out of memory)
Run Code Online (Sandbox Code Playgroud)
请参阅此处的完整讨论.注意:它在服务器Linux上不会失败.为应用程序启用了android:largeHeap ="true".
以下Java代码被称为几百次,每次调用请求~1MB:
ByteBuffer buf = raFile.getChannel().map(allowWrites ? FileChannel.MapMode.READ_WRITE : FileChannel.MapMode.READ_ONLY, offset, byteCount);
Run Code Online (Sandbox Code Playgroud)
避免请求一个通常难以找到的大的连续内存块.请在此处查看完整代码.请记住,将"段大小"(即单个地图调用的大小)加倍无效,这意味着它会停在相似的内存位置.另外值得注意的是,两个略低于极限的应用程序正在执行正常(暗示每个进程限制).
使用多个文件而不是一个具有多个映射的文件会有帮助吗?
我已经读过,这可能是虚拟地址空间的每个进程限制.哪里可以找到更多相关信息?我可以用NDK更改此设置,例如如何调用ulimit?可以由madvise帮我一点吗?
更新
有关可在Java中使用的mmap工具,请参阅此处的答案
您的问题肯定是由虚拟地址空间耗尽造成的.可能你的问题在32位Android设备上重现,用户地址空间可用,物理上限制为2GB,无法碰撞.(虽然它可能是3GB(不太可能),并且它是在OS构建过程中配置的).可能~500 MB用于系统库,JVM及其堆.并且~1.5 GB可供您使用.
在这种情况下IMO的唯一方法 - 继续仅映射现在真正使用的文件部分,并尽快取消映射未使用的部分.您可以使用某种滑动窗口,其中只有一小部分文件将映射到内存,完成后 - 取消映射该部分,前进窗口位置并映射更新的窗口,依此类推.
此外,当您映射整个大文件时 - 您的进程成为系统内存杀手的有吸引力的受害者.因为当你读取这样的映射文件时 - 物理内存的消耗会增加,并且在某些时刻进程将被终止.
| 归档时间: |
|
| 查看次数: |
1710 次 |
| 最近记录: |