我正在尝试使用 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 doc page about virtual memory 说:
尽管 OS X 支持后备存储,但 iOS 不支持。在 iPhone 应用程序中,已经在磁盘上的只读数据(例如代码页)只是从内存中删除并根据需要从磁盘重新加载。
这似乎证实 mmap 应该适用于大于物理内存的块,但仍然不能解释为什么我会达到如此低的限制。
更新
- 这个答案很有趣,但 500MB 远低于它提到的 700MB 限制。
- 这个讨论提到了连续内存。那么内存碎片可能是一个真正的问题吗?
- 我正在使用具有 256MB 物理内存的 iPod Touch 第 4 代。
- 我研究的重点是看看在从文件加载只读数据时是否有比“继续分配直到收到内存警告”更好的方法来管理内存。
mmap
似乎是解决这个问题的好方法......
更新 2
我希望 mmap 能够与新的 64 位 iOS 版本完美配合。将在我拿到 64 位设备后进行测试。