为什么mmap在iOS上失败?

Tom*_*rle 12 memory-management mmap ios

我正在尝试使用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.
}
Run Code Online (Sandbox Code Playgroud)

为什么?

我很高兴得到一个答案,例如"700MB是虚拟内存限制,但有时地址空间是碎片化的,所以你要获得700MB但是更小的块".(这只是推测,我还是需要回答)

关于虚拟内存的Apple文档页面说:

虽然OS X支持后备存储,但iOS不支持.在iPhone应用程序中,磁盘上已有的只读数据(例如代码页)只是从内存中删除,并根据需要从磁盘重新加载.

这似乎证实了mmap应该适用于大于物理内存的块,但仍然无法解释为什么我会达到如此低的限制.

更新

  • 这个答案很有意思,但500MB远低于它提到的700MB限制.
  • 这个讨论提到了连续的记忆.因此内存碎片可能是一个真正的问题?
  • 我正在使用具有256MB物理内存的iPod Touch第4代.
  • 我的研究的目的是看看在从文件加载只读数据时是否有更好的方法来管理内存,而不是"保持分配直到你收到内存警告".mmap似乎是解决这个问题的好方法......

更新2

我希望mmap能够与新的64位版本的iOS完美配合.一旦我拿到64位设备,我将进行测试.

Tom*_*rle 5

经过进一步调查并阅读约翰·卡马克这篇优秀的博客文章后,我的结论如下:

  • 700MB 是 iOS 上虚拟内存的限制(截至 2012 年,32 位 iOS)
  • 它可能在单个块中可用,也可能不可用;这取决于设备状态和应用程序行为

因此,为了可靠地映射 700MB 的文件数据,有必要将其分成更小的块。

  • 出色地。链接现在重定向到贝塞斯达。 (6认同)
  • @matrixugly 这可能是因为年龄检查。输入年龄后,您可以重新加载链接,它就会起作用。我刚刚检查了一下,博客条目仍然存在。 (2认同)