Re: Allocating too much memory kills my App rather than returning NULL
Re: Allocating too much memory kills my App rather than returning NULL
- Subject: Re: Allocating too much memory kills my App rather than returning NULL
- From: Dave Zarzycki <email@hidden>
- Date: Fri, 04 Nov 2011 19:38:55 -0700
You're tripping across a fundamental aspect of how virtual memory works. For example: what do you expect will happen if you do this on an iOS device (none of which have more than 512*1024*1024 bytes of memory)?
void *x = malloc(1024*1024*1024);
assert(x);
The answer depends on whether a given operating system overcommits memory or not. In practice, all general purpose operating systems overcommit memory. This is due to this pattern:
char *x = malloc(BIG_BUFFER);
example(x, BIG_BUFFER, ...); // use a small part of BIG_BUFFER, but not all of it
free(x);
Overcommitting memory means that the virtual address space has been allocated for the memory, but not the actual physical memory to back the allocation. The actual physical memory is allocated on demand (4KB at a time) as parts of the buffer are read or written to for the first time. In other words, given prevailing design patterns, the ability to overcommit memory leads to better memory utilization, but at the risk that code may crash when attempting to actually use 100% of the "allocated" memory.
The way one reconciles this design tradeoff is by listening to the notifications that you refer to. This is actually a great pattern, because it is more multitasking friendly when multiple processes are competing for RAM.
davez
On Nov 4, 2011, at 6:40 PM, Don Quixote de la Mancha wrote:
> My iOS App Warp Life is an implementation of the Cellular Automaton
> known as Conway's Game of Life:
>
> http://www.dulcineatech.com/life/
>
> The game takes place on a square grid. Each square is known as a
> "Cell", with the Dead or Alive state of the Cell being indicated by a
> single bit to conserve memory.
>
> I store the grid as an array-of-arrays rather than a two dimensional
> array. That is, I have an array of pointers which has the same number
> of elements as there are rows. Each row is array of unsigned longs,
> with the number of elements being the number of columns divided by
> thirty-two.
>
> The user can set the size of the grid in my Settings view. I attempt
> but fail to allow the user to make the grid as large as the available
> memory will allow.
>
> My code checks that calloc() returns valid pointers for each
> allocation attempted when creating a new grid. If all the allocations
> succeed, I copy the data in the old grid into the center of the new
> one, then free() each array in the old grid.
>
> If calloc() ever returns NULL while attempting to allocate the new
> grid, I back out all of the successful allocations by passing each
> array pointer to free(). Then I display an alert to the user to
> advise them that there is not enough memory for their desired grid
> size, and suggest trying a smaller one.
>
> This all works great when I run it in the Simulator with Xcode 4.2.
> I'm pretty sure I've had this work in the Simulator in several
> previous versions of Xcode.
>
> In iOS 3.1.2 on a first-generation iPhone, 3.2 on a first-gen iPad and
> 4.3 on an iPhone 4, my App terminates before calloc() ever returns
> NULL!
>
> I have not yet tried with iOS 5 or the 5.0.1 betas, but even if this
> is an iOS bug that has been fixed, I would much rather work around it
> as I do not want to require my users to upgrade their firmware just to
> be able to run my App. Other than this one problem everything in my
> App works great all the way back to iOS 3.1.2.
>
> Even though I feel it should not be necessary to check for Cocoa Touch
> memory warnings if I am freeing all my arrays when calloc() fails, I
> did try adding an application delegate as well as creating my own base
> class for all my view controllers that do implement the memory warning
> methods. These implementations set a global flag that indicates it is
> not safe to allocate any more memory. Then instead of calling
> calloc() directly, I call a custom allocation function that returns
> NULL if that flag is ever set. Only after freeing all the arrays do I
> reset the flag to enable further allocations.
>
> I set breakpoints at each of the memory warning methods, but my
> breakpoints are never hit. I also tried breaking on Objective-C
> exceptions but no exceptions are thrown. After my App terminates, the
> debugger GUI indicates that my app is paused - GDB doesn't seem to
> know that my App has actually been killed. I have to press the Stop
> button in Xcode to let GDB know that it's time to quit.
>
> If y'all think this is an as-yet-unreported bug in the iOS I will be
> happy to file a report, but I would be even happier if someone could
> suggest a workaround. I've been beating my head against this for a
> couple days now.
>
> Thanks!
>
> Don Quixote
> --
> Don Quixote de la Mancha
> Dulcinea Technologies Corporation
> Software of Elegance and Beauty
> http://www.dulcineatech.com
> email@hidden
> _______________________________________________
>
> Cocoa-dev mailing list (email@hidden)
>
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden