16GB memory limit for iPad apps running on Apple Silicon Macs

I seem to be hitting a 16GB memory limit for my iPadOS app running under macOS on Apple Silicon.

I can't find this limit documented or discussed anywhere else, so I'm posting here in the hopes of getting confirmation that it's official (as opposed to coincidental) and seeing if there's a way to lift or remove this limit.

Background

I have an iOS / iPadOS app that uses concurrency to solve puzzles. I have a ******* Test Puzzle that I use to stress-test the app.

The ******* Test Puzzle results in millions of NSBlockOperations on a NSOperationQueue with a concurrency limit of ProcessInfo.processInfo.activeProcessorCount - 1

The app also uses Swift "copy on write" semantics to give each operation its own variation of the game model struct, so there are corresponding Swift.***Storage objects as well.

Each of these objects is small (272 bytes for the block operations) but collectively, they add up to several GB. During a successful run, the peak memory usage of the app exceeds 50GB, as measured by Instruments and macOS Activity Monitor.

When running the iPad app on the Apple Silicon Mac, it receives a memory warning (AppDelegate.applicationDidReceiveMemoryWarning) when usage hits 16GB. The app normally halts the solver and displays an error when that happens, but if I disable the watchdog, it crashes just as it would on a real iPad.

Where it works and doesn't

The app does not run out of memory when I build for Mac Catalyst or the Xcode Simulator:


Hardware Xcode Simulator Mac Catalyst "Designed for iPad"
2018 Mac mini, Core i3, 64GB RAM  ✓  ✓  (n/a) 
2023 MacBook Pro, M2, 96GB RAM  ✓  ✓  ❌

Note: the choice of simulator is irrelevant. Even an iPod touch simulator runs to completion.

What does the kernel say?

In both the Catalyst and Simulator scenarios, os_proc_available_memory() reports 0 which I assume means "no limit."

Whereas, under "Designed for iPad" it reports 17164220800 i.e. 16GB.

So I assume this is a deliberate limit… I just see no documentation around it.

What I've tried

  • Increased Memory Limit

I've tried adding the com.apple.developer.kernel.increased-memory-limit entitlement to the app. No change.

— I've verified that the entitlement shows up in Xcode under Signing & Capabilities.

— I've verified that the entitlement shows up in my developer account under Certificates, Identifiers & Profiles.

— I've tried Quinn's trick of adding the additional Private VPN entitlement to the Mac build just to make sure Xcode picks it up.

  • Extended Virtual Addressing

I've tried adding the com.apple.developer.kernel.extended-virtual-addressing entitlement to the app. Made it worse.

The app now runs out of memory at ~3.2GB.

Note

I don't see a forum tag specifically for questions related to "Designed for iPad apps running on Apple Silicon Macs," but please educate me if I missed one.

how much memory does an app get on a physical iPad? it could be sandboxed to physical hw limits, so great question (is it documented anywhere).

50GB seems ripe for optimization btw, why do you need the entire dataset in memory?

how feasible would it be to run multiple app instances, with each instance restricted to one tree that has a max size of 16GB?

The limit on a physical iPad varies by device. The highest I'm aware of is 12GB with the entitlement, 5GB without. That's on an iPad Pro with 16GB of physical RAM. Again, there's no official documentation. That's just what others have reported here and on other sites.

This thread isn't really about optimizing my specific app, it's about the system limits apparently being imposed on iPad-on-Mac apps, which I haven't seen discussed anywhere else.

But to answer your other questions briefly:

  • It isn't really "my" memory, it's the overhead of the NSOperationQueue and Swift copy-on-write. My "dataset" is quite small, there just happen to be lots of copies of it floating around in memory as each possible permutation gets explored. The 50GB is a peak; actual memory usage varies considerably during the run as the queue drains and refills and the Swift runtime collects its garbage.

  • Not feasible at all. This is a shipping app that needs to pass App Store Review.

Keep in mind that I'm running a stress test that is not representative of real-world, human-scale puzzles. Actual puzzles from magazines, Sunday Times, etc. get solved in under a second with 0.1MB - 0.2MB of memory consumption.

I was just hoping that I could run the stress test on the actual, shipping App Store build using my new M2 MBP that I picked up this week. But apparently not.

16GB memory limit for iPad apps running on Apple Silicon Macs
 
 
Q