As explained in Reclaiming memory from Metro style apps, Windows 8 optimizes the way RAM is dedicated to running processes. Metro Apps are even more impacted than just reclaiming memory from their working set because the system can decide to simply terminate the suspended ones when low memory conditions are detected. It is important to take care of this scenario when you write your code so the user, who is unaware of the App termination expects to get back where he was when he clicks on its tile: this is part of the PLM (= Process Lifecycle Management) and I’ll spend some time describing the basics before returning to the hidden termination case.
Download ByeBye tool.
In previous versions of Windows,
Main was the only single entry point called by the system to start your application via the main thread process. In Wndows 8, a Metro App provides several entry points by implementing the
By default, your
Application derived class code usually implements only the
OnLaunched method that is called when the user clicks the App tile. The other methods are called when the App gets activated via different Contracts such as Search or Share target as explained in Activating Windows 8 contracts in your app.
Each method receives an instance of a type inherited from
that provides three properties:
Kind property repeats the activation reason via the
ActivationKind enumeration. The
SplashScreen property references an object that lets you know where the splashscreen bitmap you defined in the App manifest is displayed on the screen and also when it is dismissed (see the Extended Splashscreen SDK Sample for implementation details about how to use it).
PreviousExecutionState property tells you what is the reason why your App ends its life at the end of its previous execution.
- If the user closed the App by using ALT+F4 keyboard shortcut or via the swipe downward touch gesture, the
Suspendingevent is first received so you can save anything you need before Windows closes the App. In that case, your activation override will receive the value
PreviousExecutionStateproperty and you are supposed to display the main page of the App.
Runningvalue is received by the overrides related to Contracts (all except the
OnLaunchedoverride) when the App is already running.
- Same for the
Suspendedvalue which is received when the App gets activated by a Contract while it is suspended.
- If the App was never started since the user logged in or crash, the value will be
Terminatedvalue is set by Windows when the App was terminated due to system optimization such as in the case of low memory condition I mentioned earlier. The default Visual Studio template for Metro App generates code that handle this special case and let you know where to restore your state with the following comment
//TODO: Load state from previously suspended application
Unlike the activation methods your application code implement from
Suspending and the
Resuming events are defined in the
IApplication interface that your
Application type also implements:
You usually register listeners in the Application constructor. The
Suspending event is triggered around 10 seconds after the App leaves the foreground when the user decides to use another App (either Metro or Desktop application). In some cases such as games, you don’t want you App to run in the background for 10 seconds without any user interaction. You can use a nice trick to be notified immediately by registering a listener to the
VisibilityChanged event in the current navigated to window. Here is the schedule of these events traced by
Debug.WriteLine calls intercepted by the DebugView tool from SysInternals as I’ve already explained :
What are you supposed to do in your
Suspending event handler? Well… save the state corresponding to what the user is doing (remember that you are supposed to restore this state in the application overrides only when the previous state is
Terminated). A good example is the Mail App that saves the text the user enters while writing an email. That way, if Windows decides to terminate the App, when it will be reactivated, the same state will be restored without the user even noticing anything. See Process Lifetime Management (PLM) and Managing State in Windows 8 Metro C# Applications by Jeremy Likness from Wintellect to get the details of current navigation save/restore feature provided by the Visual Studio C# templates.
If you take more than 5 seconds to save your App state, Windows will terminate it because it is assuming that your code has a bug and should not continue to run. This value of 5 seconds is given by the
Deadline property of the
SuspendingEventArgs provided to the
Suspending event handler:
When the App gets suspended, Windows stops scheduling its threads until it gets resumed by the user. The Windows TaskManager allows you to detect such suspended Apps but you first have to check the View | Status values | Show suspended status menu item:
How to debug automatic termination and contract activation
Debugging your overrides and
Resuming handlers is not an obvious task. Why? Because a Metro App behaves in a different way while running under the control of a debugger such as Visual Studio. In that case, the threads are never suspended because otherwise the Debugger would also be suspended. So, a debugged Metro App will never receive the
Suspending event even though it is in the background while the user uses another application. As explained in How to trigger suspend, resume, and background events in Metro style apps, Visual Studio provides special toolbar commands to emulate these events.
While I’m talking about Visual Studio, let’s quickly see how to debug your activation overrides. If you debug your Metro App, Visual Studio will start the App. However, this is not what you want to debug your activation overrides such as when the user submit a search string while your App is not running already (yes… your App has to support this kind of activation :^). In that case, you need to change the Debug project configuration and check the “Do not launch, but debug my code when it starts“ setting:
Now, when you debug your App, nothing visible happens. However, when you activate the App via any supported contract, the breakpoints you’ve set in the corresponding override are triggered and you jump into Visual Studio debugging experience.
How to test automatic termination
If you need to test that your application behaves appropriately outside of a Visual Studio debugging session, things are getting a little more complicated. Before the Release Preview, you simply needed to wait for the App to get suspended and right click it in TaskManager to choose the End Task context menu item. The next time the App was started, the handlers would have received the right
Terminated state. Unfortunately, this is no more the case.
I’ve noticed that if you start (not debug) the application from Visual Studio while it is running, it gets terminated the right way and the
Terminated value is received as expected. However, what to do if there is no Visual Studio installed? This is the role of my new ByeBye tool:
When you click the “Add Memory Pressure” button, it sets its own maximum working set size to the size of the RAM in the machine and starts to allocate chunks of 256MB of commited memory until it detects that Windows is running under low memory condition. At that moment, it stops allocating chunks and the chip logo starts to blink:
Click the now renamed “Remove Memory Pressure” button to free the allocated chunks.
Here is the list of the APIs used by the tool:
- GetProcessMemoryInfo: get the working set size of the current process
- GlobalMemoryStatus: get the machine RAM size and the current system memory load
- SetProcessWorkingSetSize: set the current process working set min and max sizes
- VirtualAlloc: allocate chunk of commited memory with the MEM_COMMIT/PAGE_READWRITE parameters
- CreateMemoryResourceNotification/QueryMemoryResourceNotification: check if under low memory condition
As you can see, the tool uses brute force to emulate low memory condition that forces Windows to reclaim memory from Metro Apps, up to terminate most of them. However, it might happen that the pressure is not even enough and that you might have to repeat memory pressure in ByeBye in order to force Windows to terminate your App.
I hope this helps