Action Extension Memory Limit Crashes

I have an app with an action extension that takes a photo (the app only) or grabs a photo from a 3rd-party app or within the app itself, e.g. Photos, adds an imprint, e.g. date, and then adds a new photo to an album, Camera Roll. The app itself has no issue doing that for any photo in any app (lots of memory). But the extension crashes when the original photo is over ~8mb with some hard memory limit (120mb). But when I watch the memory use, it stays around 20mb, and when I initiate the stamped overlay, it briefly goes to 80mb, and then back down to 20mb and then crashes.


The error is EXC_RESOURCE RESOURCE_TYPE_MEMORY (limit=120 MB, unused=0x0). Finally, I found that problem resides in a method where I add the imprint by drawing the original image in a graphic context using drawInRect: and then drawing the overlay into the same context and converting it to a UIImage and returning that to the caller. The app crashes at drawInRect: with vImage`_ERROR_Buffer_Write__Too_Small_For_Arguments_To_vImage__CheckBacktrace:


With larger megapixel phones, this has caused me to remove my app from the App Store, and It sure doesn't seem like I've broken any programming rules.


Does anyone know how to fix this kind of issue/crash?

  • @DrMiller have you managed to fix the issue? I have the same problem. I have an Audio Unit that runs as a sand-boxed out-process, when I try to allocate ~30Mb it crashes (sometimes) with exactly the same error.

Add a Comment

Replies

Especially on iOS you can find yourself in this position if your application uses too much memory. Applications and especially demons are often sandboxed for memory usage. Using too much memory will yield the exception of this kind. You can read more about it here:

https://developer.apple.com/documentation/metrickit/improving_your_app_s_performance/reducing_your_app_s_memory_use

If you simply crash in this vImage function with EXC_BAD_ACCESS or similar then that is a strong indication that the buffer passed to vImage was too small, non existent or not writeable. The vImage routine simply writes a byte to the last valid byte in the vImage_Buffer to see what will happen. If all is well, it goes through and nobody notices. If the buffer is too small (depressingly common) then the write may run off the end of the buffer and cause a crash. This is a signal that the bug is in the callers code and not a problem in vImage. (As the framework ultimately responsible for touching potentially improperly configured pixel buckets, vImage would otherwise find itself having to diagnose a lot of other people's bugs, so it is there as a means of self defense.) You can use vImageBuffer_Init to allocate buffers for you to help reduce this sort of error. Otherwise, you can use vmmap <pid> to dump a list of the application's allocations to go look at whether the crash data address is in the buffer that it is supposed to be in or somewhere off the end. Vmmap will also tell you whether the allocation is readonly or readwrite. If you aren't the one calling vImage directly, then the error might lie in the callers code, or potentially could be in an incorrectly allocated CFData, CGImageDestination, or similar. Where are those pixels supposed to end up? Look there.

Note that vmmap shows the view of memory from the perspective of virtual memory -- the set of large page aligned allocations that underlie what is going on in the system. It is also the granularity along which memory protection functions. For smaller allocations, malloc() allocates a biggish chunk of page aligned memory and then sub allocates from there as needed. So, while you will see the large page aligned buffer that contains your 16-byte allocation, it won't be stored individually as such, unless MallocGuardEdges, GuardMalloc or similar is on.

Also actual for me. I am trying to apply exposure filter on local video with usage of ffmpeg-kit library and got: Thread 358: EXC_RESOURCE (RESOURCE_TYPE_MEMORY: high watermark memory limit exceeded) (limit=2098 MB)