【发布时间】:2012-11-16 22:45:43
【问题描述】:
我正在尝试使用 mmap 在 iOS 上读取和播放音频文件。它适用于最大约 400MB 的文件。但是当我尝试一个 500MB 的文件时,我得到一个 ENOMEM 错误。
char *path = [[[NSBundle mainBundle] pathForResource: @"test500MB" ofType: @"wav"] cStringUsingEncoding: [NSString defaultCStringEncoding]];
FILE *f = fopen( path, "rb" );
fseek( f, 0, SEEK_END );
int len = (int)ftell( f );
fseek( f, 0, SEEK_SET );
void *raw = mmap( 0, len, PROT_READ, MAP_SHARED, fileno( f ), 0 );
if ( raw == MAP_FAILED ) {
printf( "MAP_FAILED. errno=%d", errno ); // Here it says 12, which is ENOMEM.
}
为什么?
我很乐意回答“700MB 是虚拟内存限制,但有时地址空间是碎片化的,所以你确实得到了 700MB,但是以更小的块”。 (这只是猜测,我还需要答案)
有关虚拟内存的 Apple 文档页面说:
虽然 OS X 支持后备存储,但 iOS 不支持。在 iPhone 中 应用程序,已在磁盘上的只读数据(例如代码 pages) 只是从内存中删除并根据需要从磁盘重新加载。
这似乎证实 mmap 应该适用于大于物理内存的块,但仍然不能解释为什么我会达到如此低的限制。
更新
- This answer 很有趣,但 500MB 远低于它提到的 700MB 限制。
- This discussion 提到连续内存。那么内存碎片可能是一个真正的问题吗?
- 我正在使用具有 256MB 物理内存的 iPod Touch 第 4 代。
- 我的研究目的是看看在从文件加载只读数据时是否有比“继续分配直到收到内存警告”更好的方法来管理内存。
mmap似乎是解决这个问题的好方法...
更新 2
我希望 mmap 能够与新的 64 位 iOS 版本完美配合。将在我拿到 64 位设备后进行测试。
【问题讨论】:
-
嗯,一个 500MB 的文件几乎是 iPhone 4 上实际可用的可用 RAM 的两倍...您期望什么?
mmap()不是魔法。 -
@H2CO3 我希望它在访问 mmapped 区域时按需将文件数据分页到 RAM 中。这不是 mmap 的作用吗?
-
这是一个实现细节你不应该依赖它,b。你不应该有任何期望,c。可以通过阅读libSystem源代码的相关部分来查找。
-
@H2CO3 256MB iPod Touch 上的 400MB 文件不会失败。
-
“没有期望”关于 mmap() 对我来说听起来不对。 mmap() 存在的全部原因(与 read() 相反)是为了让文件可以按需分页,并在 VM 系统认为合理时从物理内存中删除。即使只有一个可用的 RAM 物理页,也应该可以 mmap() 一个大文件。但是,如果您 mmap() 的范围大于最大的连续虚拟内存块,您将失败——您可能应该一次映射较小的文件段来解决这个问题。
标签: ios memory-management mmap