Why does mmap not work in iOS?

I am trying to use mmap to read and play audio files on iOS. It works great for files up to 400 MB in size. But when I try to create a 500 MB file, I get an ENOMEM error.

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. } 

Why?

I would be pleased with an answer like "700 MB is a virtual memory limitation, but sometimes the address space is fragmented, so you get 700 MB, but in smaller pieces." (This is just an assumption, I still need an answer)

The Apple virtual memory document page says:

Although OS X supports backup storage, iOS does not. In an iPhone application, read-only data that is already on disk (for example, page code) is simply deleted from memory and reloaded from disk as needed.

which seems to confirm that mmap should work on blocks larger than physical memory, but still doesn't explain why I push such a low limit.

Update

  • This answer is interesting, but 500 MB is well below the 700 MB limit that he mentions.
  • This discussion refers to continuous memory . So memory fragmentation can be a real problem?
  • I am using the 4th generation iPod Touch with 256 MB physical memory.
  • The goal of my research is to see if there is a better way to manage memory when loading read-only data from files than to "save the selection until you get a warning about the memory." mmap seemed like a good way to solve this problem ...

Update 2

I expect mmap to work perfectly with the new 64-bit version of iOS. Will check as soon as I get my hands on a 64-bit device.

+8
memory-management ios mmap
source share
4 answers

After further studying and reading this excellent blog post by John Carmack , here are my findings:

  • 700 MB is the limit for virtual memory on iOS
  • It may or may not be available in one unit; it depends on the state of the device and the behavior of the application.

Therefore, in order to reliably display the data of a file of 700 MB in size, it is necessary to break it into smaller pieces.

+1
source share

I have no answer for you, but I checked your code on my iPhone 5 running 6.0.1, and mmap succeeded in the 700 MB ISO file. Therefore, I would start with other factors and suggest that mmap is working correctly. Perhaps the error you are returning about is not actually memory related, or perhaps the memory on the device itself has somehow been exhausted to the point that mmap does not work; try rebooting the device. Depending on your version of iOS, I also wonder if your search to the end of the file can call mmap to try to display the whole file; you can try to clear this and use stat instead of determining the file size or close and then reopen the file descriptor before matching. These are all ideas; if I could reproduce your mistake, I would be happy to help correct it.

+1
source share

Use NSData and do not touch mmap directly here.

To take advantage of read errors, use NSDataReadingMapped. NSData ALSO frees bytes in low memory situations

0
source share

Usually the amount of available physical memory has nothing to do with whether you know how to mmap a file. This is VIRTUAL memory that we are talking about. The problem with iOS is that, at least according to the iOS app programming guide, the virtual memory manager replaces read-only partitions ... In theory, this means that you are not only limited by the amount of available address space, but you are also limited the amount of RAM available if you match anything other than PROT_READ. See http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/TheiOSEnvironment/TheiOSEnvironment.html

However, it is entirely possible that the problem you are facing is the lack of contiguous memory large enough for your mapping in the virtual address space. As far as I can find, Apple does not publish the upper limit of memory in user mode. Typically, the top address space is reserved for the kernel. You can only have 16-bit memory for working in user mode.

What you cannot see without resetting the memory card in the debugger is that a lot of shared libraries (dylib) were loaded into the address space of the process (I counted more than 100 in a simple sample program from Apple). Each of them is also mmap'd, and each fragment of the available address space.

In gdb, you should be able to unload memory mappings using "file information mappings". Unfortunately, in lldb, the only equivalent I managed to find is the "image list", which displays only library mappings, not mmap mappings.

Using the debugger in this way, you can determine if the address space has an adjacent block large enough for the data you are trying to match, although it does some work to detect the upper limit (Apple should post this!)

0
source share

All Articles