Device memory
Windows
Phone 7.x apps are limited to using 90 MB of memory; that is, the app
is promised that it can use up to 90 MB, and that while it might
sometimes get more, there is no guarantee of this. So, 90 MB is
effectively both the minimum and the maximum on which a version 7.x app
can rely. In addition to that, one of the certification requirements
for version 7.x apps is that they must not consume more than 90 MB.
What has happened in practice is that while most apps (well over 95%)
stayed well below the 90 MB cap, there were a few that did not. Even
within these few, there was an extremely small number of apps that
consistently exceeded the cap by a significant amount. When an app
exceeds the cap, it runs the risk of running out of memory. That is, if
the device is under extreme memory pressure, and the app is attempting
some operation that requires the system to allocate it memory which it
cannot grant, the allocation will fail. In this case, an OutOfMemoryException is thrown, and if the app doesn’t catch this, it will crash. If you do catch an OutOfMemoryException,
you’re still faced with the dilemma of what to do with it. You must
reduce your memory consumption, and you must be careful to perform this
clean-up in a way that doesn’t inadvertently attempt to allocate more
memory; otherwise, you’ll simply fail again.
The version 7.1.1 release of Windows Phone seems at first sight
somewhat anomalous. Although the min/max guarantee (and Windows Phone
Store certification requirement) for 7.1.1 remains at 90 MB, the OS can
actually safely allocate an app up to 110 MB. The primary purpose of
the 7.1.1 release was to support markets where devices with only 256 MB
of total memory are common, and it’s not immediately obvious why a
release that targets devices with restricted memory should increase the
app memory cap rather than reduce it. The reason this makes sense is
that version 7.1.1 introduced paging, and could satisfy the higher cap
by adding virtual memory to the physical memory allocation for an app.
Paging is a technique uses by desktop and server operating systems to
write out memory to a hard disk, thereby freeing up physical memory. An
app can consume more memory than is physically available because the
amount of memory the OS commits to the app can include space in the
page file, which is therefore virtual memory. The cost of paging is
slower performance, however, so it is used as a last resort. In
addition, the 110 MB cap is strictly enforced on devices with only 256
MB of memory. That is, on a version 7.1.1 device with 256 MB memory, if
your app attempts to allocate memory beyond 110 MB, the allocation will
fail. On a version 7.1.1 device with more memory, the model is the same
as for versions 7.0 and 7.1; that is, it might fail, and it might not,
depending on the circumstances. The feedback from developers—strongly
echoed by the Windows Phone product team—was that it would be useful to
get more than 90 MB of memory. Conversely, it is not useful to provide
additional memory in a nondeterministic manner. Developers seemed to
prefer the 256 MB version 7.1.1 model, wherein the app is granted a
deterministic 110 MB always, and no more.
Windows Phone 8 also implements paging and also makes the caps
completely deterministic. There are two memory caps for all Windows
Phone 8 apps: a default MIN_CAP and an optional MAX_CAP. The values of these caps vary by app type and by device configuration, as shown in Table 2.
Table 2. Windows Phone 8 memory cap values
Cap
|
Low-memory devices
|
High-memory devices
|
Default for XNA/Native aps |
150 MB |
150 MB |
Default for non-XNA Managed apps |
150 MB |
300 MB |
Optional higher cap for all apps |
180 MB |
380 MB |
The labels “low memory” and “high memory” in this table need some
explaining. Simplistically, “low memory” means ≥512 MB and <1 GB,
whereas “high memory” means ≥1 GB. However, this is not necessarily
always accurate. Internally, the computation takes into account any
additional memory that is carved out for unusual hardware capabilities.
For example, if a device manufacturer ships an extremely
high-resolution camera and then needs to carve out a large amount of
additional memory for device drivers for this camera, this will reduce
the total amount of memory available to the app. If this amount falls
below a certain threshold, the device will be treated as a low-memory
device, even if it nominally has ≥1 GB. That being said, as of this
writing, all devices with ≥1 GB memory are in fact treated as
high-memory devices.
To support these caps, the Windows Phone 8 app manifest supports two new optional app manifest tags, as shown in Table 3.
Table 3. New Windows Phone 8 memory-related manifest entries
Manifest entry
|
Description
|
Memory cap
|
ID_REQ_MEMORY_300
|
Opts out of low-memory devices: the app will be filtered out in marketplace and will not install on a low-memory device. |
The default cap (On high-memory devices, 150 MB for XNA/Native apps, and 300 MB for non-XNA Managed apps). |
ID_FUNCCAP_EXTEND_MEM
|
Does not opt out of low-memory devices (installs on all devices) but
is granted the optional higher cap instead of the default cap. |
The optional higher cap (180 MB on low-memory devices; 380 MB on high-memory devices). |
App memory is capped to ensure a balanced user experience, with cap values that make the following possible:
-
Developers can develop for all devices, especially the high-volume, low-memory devices.
-
Developers can build apps that use more memory if it is available.
-
Adjusts for the fact that a non-XNA managed app’s memory consumption
goes up on WXGA devices due to auto-scaling of high-resolution
graphics. All 720p and WXGA devices have ≥1 GB memory.
The new memory cap flags are not surfaced in the Visual Studio UI at
all. You must edit the manifest manually. The order of the tags in the
manifest is important, and it’s different between a Windows Phone 7.1
app manifest and a Windows Phone 8.0 app manifest. For Windows Phone
7.1, the Requirements section should immediately follow the Capabilities section. The FunctionalCapabilities section, if present, should immediately follow the \Requirements section. For Windows Phone 8.0, both Requirements and FunctionalCapabilities sections should be at the end, just before the closing </App> tag, in that order. That is, the Requirements section should follow the ScreenResolutions section.
To get the higher memory cap, add this tag inside the <App> tag:
<FunctionalCapabilities>
<FunctionalCapability Name="ID_FUNCCAP_EXTEND_MEM" />
</FunctionalCapabilities>
To opt your app out of low-memory (512MB/768MB) devices, add this tag:
<Requirements>
<Requirement Name="ID_REQ_MEMORY_300" />
</Requirements>
If you want both opt-out and higher-cap, your Windows Phone 8.0 manifest should look like this:
<App …>
…
<Requirements>
<Requirement Name="ID_REQ_MEMORY_300" />
</Requirements>
<FunctionalCapabilities>
<FunctionalCapability Name="ID_FUNCCAP_EXTEND_MEM" />
</FunctionalCapabilities>
</App>
And, your Windows Phone 7.1 manifest would be as shown in the
snippet that follows. Be aware that a Windows Phone 7.1 manifest might
also include ID_REQ_MEMORY_90 to specify behavior for 256 MB Windows Phone 7.1.1 devices.
<App …>
<Capabilities>
…
</Capabilities>
<Requirements>
<Requirement Name="ID_REQ_MEMORY_90" />
<Requirement Name="ID_REQ_MEMORY_300" />
</Requirements>
<FunctionalCapabilities>
<FunctionalCapability Name="ID_FUNCCAP_EXTEND_MEM" />
</FunctionalCapabilities>
<Tasks>
…
</Tasks>
<Tokens>
…
</Tokens>
</App>
ID_REQ_MEMORY_90
only opts the app out of 256 MB Windows Phone 7.1.1 devices, and if you
additionally want to be opted out of low-memory Windows Phone 8
devices, then you must include ID_REQ_MEMORY_300. Keep in mind that ID_REQ_MEMORY_300 opts the app out of both, so if you have ID_REQ_MEMORY_300, you don’t need ID_REQ_MEMORY_90; if you do have both ID_REQ_MEMORY_300 and ID_REQ_MEMORY_90, the ID_REQ_MEMORY_90 is ignored.
If you opt out of low-memory devices, your app knows statically how
much memory it can use, because this is dependent only on the type of
app (XNA, non-XNA managed, or native) and whether or not the app
manifest includes ID_FUNCCAP_EXTEND_MEM,
both of which are known. If you don’t opt out of low-memory devices,
you can’t completely know statically what your memory cap will be,
because it also depends on what configuration of device on which the
app happens to be running. In this scenario, you can determine this
dynamically by using the memory-related properties on the DeviceStatus class. Specifically, ApplicationMemoryUsageLimit notifies you of the cap that this specific system is enforcing on your app, and ApplicationCurrentMemoryUsage informs you how much memory you’re currently consuming.
long cap = DeviceStatus.ApplicationMemoryUsageLimit;
long current = DeviceStatus.ApplicationCurrentMemoryUsage;
Armed with this information, you can then make appropriate
choices to conditionally enable/disable features in your app to
accommodate the lower/higher memory caps. You can use the different
emulator images available in Visual Studio to test your app on
different device configurations. The simplest approach is to start by
just running your app and check memory usage in the profiler. Then, if
it needs too much and you can’t reduce it, add the right flags.