I've received a lot of questions over the last while as to how the Windows Mobile shell handles low memory on both Pocket PC and Smartphone and I thought it's about time somebody gave a decent explanation as to how the shell handles this situation. This is mostly an FYI post but hopefully if you're writing an app for Windows Mobile you'll also stop and consider how well your app will behave when confronted by a device running low on resources.
To start, low memory is a very important consideration to take into account when dealing with a resource constrained device such as a Pocket PC or Smartphone (or any other embedded device for that matter). Unlike the desktop we don't have a large source of memory to tap and no virtual memory (since we don’t require a device to have secondary storage that we could swap memory out to) so a device can quickly get into a state where most of the available memory is in use.
The Windows Mobile 5 shell runs a low memory check routine periodically (on Pocket PC this is done every 5 seconds, on Smartphone its 30 seconds) and assesses the state of the system memory. The routine will check to see if any action is required to keep a reasonable amount of memory free (the OEM ultimately decides what a reasonable amount is). Additionally, the kernel also monitors the amount of memory available and will nudge the shell whenever free memory drops below a certain threshold.
Below is a simplified diagram of the memory available for a device and the different memory thresholds that exist (note that the diagram is meant to show the relationship between thresholds and do not reflect relative values or sizes. Also, these threshold values can be modified by the OEM so there is no single value for them).
This is the amount of memory the shell tries to keep free at all times. If the amount of free memory falls below this value then the low memory check routine will try to free up memory. It will do this by first sending WM_HIBERNATE to all valid applications. When an application receives this message it should try to free as many resources as possible. When the low memory check routine runs again and the amount of free memory is still below the hibernate level then the shell will try to close the least recently used (LRU) application by sending a WM_CLOSE message. If the low memory check routine runs yet again and the amount of free memory is still below the hibernate level then the shell will call TerminateProcess on the LRU application that it last sent the WM_CLOSE message to.
If the low memory check routine is entered and the free memory is below this value the shell will send a WM_HIBERNATE message to all valid applications as above but it will then immediately try to close the LRU application without waiting to see if the WM_HIBERNATE messages were successful in bringing the amount of available memory above the critical level.
When launching an application the shell checks that there is at least this amount of memory free, otherwise it fails the application launch. This is done in order to prevent the application from taking up the last bit of available memory and potentially starving already running applications.
Kernel - Check
This is the value that the
Pocket PC – An "out of memory" dialog is displayed prompting the user to select an application to shut down.
Smartphone – The LRU application is closed without prompting the user.
For an application to be considered by the low memory check routine as a candidate to receive a WM_HIBERNATE message or to be closed (if it’s the LRU application) it must meet the following criteria:
1. Have a top level window
3. Have been activated at some point
4. Not the foreground application (since this is the app the user is interacting with and they'd probably be pretty mad if it started to free resources as a result of receiving WM_HIBERNATE or was closed while they were using it)
What can my Application do?
The best thing your application can do when faced with a low memory situation is to play nicely with the rest of the device.
If your application receives a WM_HIBERNATE message free up any resources not absolutely required.
If you are planning on allocating a large amount of memory (or if a large allocation fails) you should call SHCloseApps, which will invoke the shell low memory check routine and will try to ensure that enough free memory exists. See below for an example:
#define MIN_MEMORY_TO_RUN 2*1024*1024
mst.dwLength = sizeof(MEMORYSTATUS);
If (mst.dwAvailPhys < MIN_MEMORY_TO_RUN)
// Try to free memory by asking Shell to shutdown apps
// Handle the case where memory could not be freed