The stack is the memory set aside as scratch space for a thread of execution. When a function is called, a block is reserved on the top of the stack for local variables and some bookkeeping data. When that function returns, the block becomes unused and can be used the next time a function is called. The stack is always reserved in a LIFO (last in first out) order; the most recently reserved block is always the next block to be freed. This makes it really simple to keep track of the stack; freeing a block from the stack is nothing more than adjusting one pointer.
The heap is memory set aside for dynamic allocation. Unlike the stack, there's no enforced pattern to the allocation and deallocation of blocks from the heap; you can allocate a block at any time and free it at any time. This makes it much more complex to keep track of which parts of the heap are allocated or freed at any given time; there are many custom heap allocators available to tune heap performance for different usage patterns.
Each thread gets a stack, while there's typically only one heap for the application (although it isn't uncommon to have multiple heaps for different types of allocation).
To answer your questions directly:
To what extent are they controlled by the OS or language runtime?
The OS allocates the stack for each system-level thread when the thread is created. Typically the OS is called by the language runtime to allocate the heap for the application.
What is their scope?
The stack is attached to a thread, so when the thread exits the stack is reclaimed. The heap is typically allocated at application startup by the runtime, and is reclaimed when the application (technically process) exits.
What determines the size of each of them?
The size of the stack is set when a thread is created. The size of the heap is set on application startup, but can grow as space is needed (the allocator requests more memory from the operating system).
What makes one faster?
The stack is faster because the access pattern makes it trivial to allocate and deallocate memory from it (a pointer/integer is simply incremented or decremented), while the heap has much more complex bookkeeping involved in an allocation or deallocation. Also, each byte in the stack tends to be reused very frequently which means it tends to be mapped to the processor's cache, making it very fast. Another performance hit for the heap is that the heap, being mostly a global resource, typically has to be multi-threading safe, i.e. each allocation and deallocation needs to be - typically - synchronized with "all" other heap accesses in the program.
A clear demonstration:
Image source: vikashazrati.wordpress.com
In general, don't unload views unless you have to (didReceiveMemoryWarning
) or it makes sense (something like a login form that's unlikely going to be used again).
You can't really assume that you have a fixed amount of memory. iPhone's have less memory than iPod touches. iPhone 3GS's have more memory than either. Jail-broken handsets often have substantially less memory.
By only releasing views when you have to you're making your app run faster on the 3GS and allowing it to run when there's less memory available.
The didReceiveMemoryWarning
method releases the view if it is not visible. The following is from the documentation (v3.x):
The default implementation of this
method checks to see if the view
controller can safely release its
view. This is possible if the view
itself does not have a superview and
can be reloaded either from a nib file
or using a custom loadView method. If
the view can be released, this method
releases it and calls the
viewDidUnload method.
Obviously you also need to release any cached data. SDK2.x does not have the viewDidUnload
method.
Best Answer
First of all, these are just guidelines, so if you don't think it makes good sense to release something in
didReceiveMemoryWarning
then don't do it. But keep in mind that if your application is the one that is causing the memory warning in the first place then it will eventually just be terminated by the OS.Re (1): Critical vs. non-critical is entirely your call. Only you can really determine what data you're holding that you consider critical. Though it's probably going to be closely related to your (3), that is, something that is easily recreated is probably not too critical.
Re (2): I don't think the statement is in reference to the order of the calls. As you have realized, in general,
viewDidUnload
is going to get called afterdidReceiveMemoryWarning
(sincedidReceiveMemoryWarning
can causeviewDidUnload
to be called). As an example, inviewDidUnload
one will release references held to UI elements from a nib. So don't also release them indidReceiveMemoryWarning
.Re (3): If a view is in use and thus can't be unloaded, then yes, obviously it doesn't necessarily make much sense to release it in
didReceiveMemoryWarning
. However, you may actually have instances where a view couldn't be unloaded, but is known to not be visible (not terribly normal), in which case it might make sense to unload it's data and recreate it when the view is visible once again.Additionally, I agree the "Instead, you should consider..." remarks are a bit odd, but again I think the point of recommending the data be released in
didReceiveMemoryWarning
stems from the fact that if you're receiving those warnings then your own app might be in danger of being terminated. So while it is currently the case thatviewDidUnload
probably is always called as the result of a memory warning, that may not always be the case in the future and so conceptually it makes more sense to release the data indidReceiveMemoryWarning
itself. IndidReceiveMemoryWarning
you KNOW there is memory pressure, inviewDidUnload
you may not. So while it's true that the data will then be expensive to recreate, that might be better than having your app terminated. To the user it will appear as though the app crashed.My own personal approach to those methods is generally this:
viewDidLoad
.viewDidLoad
is called again (or some other app specific event). Do NOT release anything that I can't possible recreate.