did stack allocation limit changed on recent iOS ?

I have a recursive algorithm which was tested on devices and ran ok before. It still runs ok on an iPhone4/iOS7, but not on devices running iOS 9.2+.

The crash is "memory bas access", not specifically stack overflow documented.

I wonder if this is some side effect bug in my code or if the runtime changed in recent IOS release, allowing less stack allocation.

The code still also runs ok in simulator with iOS 9.3 runtime.


For information, the recursion may be as much as 15k, with small parameters and variables space so is estimated as 100kb maximum stack requirement. Current crashes occur arout 3-4K call deep.


Any though ?

Investigating on the subject. I found that stack size is 1Mb for main thread.

Also, by cheking parameters address on the stack crawl on crash, I can see that the stack size is exhausted.

This is the point I don't get. The recursion is coded by a block. To avoid the retain cycle, two block variables are declared, one is weak and retained from the block. (see http://stackoverflow.com/questions/14839571/block-recursion-and-breaking-retain-cycle/26658513#26658513)

So the question becomes : is the block copied on the stack on each recursive call ? On else what could cause such a stack bloating on block call ?

Still no clues as why it's running ok on some devices. The 32/64 bits should not play, all local variables are fixed sizes.


Edit: After more investigations, I slimed down local variables in the block to a bare minimum. Nevertheless, it turns out that block invocation push about 90 bytes on the stack, beside parameter or return value. Also this is a minimum since, depending of the way the block is declared this might be more. All in all I'm not able to recurse more than 9k deep and this does not meet the requirement for the algoritm.


So it turns out I have to change to a non recursive algo, which is significantly slower.


Why was it working before, and still is on some devices/iOS, is still unknown.

The stack size configuration is likely to be differemt on different devices and iOS versions, because it's a less documented feature. And the available stack depth is going to vary. (The simulator isn't an emulator, it's an OS X process running a quick impersonation of the iOS environment. So "It works in the simulator" doesn't mean anything.)


If you're writing a recursive block algorithm, one of the things you have to be careful about is how much scope the block captures, because that's going to increase the overhead of each block invocation.

The 32/64 bits should not play, all local variables are fixed sizes.

Except for the saved return address. And the register spill area. And, well, you get the idea.

If you’re going to recur thousands of stack frames deep, you probably want to do that on a secondary thread. That way the pages allocated to the stack can be reclaimed when the work is done and your thread terminates.

Realistically though, this much recursion is almost always a bad idea. You wrote:

So it turns out I have to change to a non recursive algo, which is significantly slower.

I find that hard to believe. Non-recursive implementations are almost always more efficient than recursive ones. Now significantly harder to write is something that I can believe.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
did stack allocation limit changed on recent iOS ?
 
 
Q