[Tips and Tricks] Windows Phone. DeviceStatus. Uso de memoria

memory-chipIntroducción

Por encima de cuidar detalles como la funcionalidad o la estética de nuestra aplicación, tenemos que lograr un objetivo que parece simple pero que a veces se escapa, nuestra aplicación debe funcionar correctamente bajo todas las condiciones en todos los dispositivos para la que sea lanzada. Un fallo comun suele ser que se escape la gestión de memoria de la aplicación pudiendo obtener una excepción de tipo OutOfMemoryException. Ya vimos como el control MemoryCounter del Coding4Fun Toolkit nos ayuda a saber el uso de memoria en todo momento. También tenemos disponible la herramienta Windows Phone Performance Analysis para poder analizar el uso de memoria de nuestra aplicación entre otras opciones. Sin embargo, el propio SDK nos incluye la posibilidad de saber el uso de memoria de nuestra aplicación e incluso el límite máximo de uso de memoria o la memoria disponible del dispositivo. Vamos a aprender como realizar esta tarea en este artículo.

Monitorizar la memoria

Tenemos disponible en el SDK de Windows Phone la API DeviceStatus que nos permite obtener información del hardware del dispositivo como la cantidad de memoria o la versión del sistema por ejemplo. Además, tenemos disponible una serie de eventos a los que podemos suscribirnos para recibir una notificación cuando un parámetro del sistema cambia.

Vamos a realizar un ejemplo práctico donde utilizar la API DeviceStatus. Creamos un nuevo proyecto:

La plantilla seleccionada será “Windows Phone Application” para simplificar al máximo el ejemplo. Comenzamos creando la base de nuestra interfaz. Añadiremos dos botones, uno para aumentar el consumo de memoria y otro para liberarla:

<Button Content="Aumenta consumo memoria"/>
<Button Content="Libera consumo memoria"/>

Añadimos sus eventos clic:

<Button Content="Aumenta consumo memoria" Click="AumentaMemoria_Click" />
<Button Content="Libera consumo memoria" Click="LiberaMemoria_Click"/>

Y en el code-behind:

private void AumentaMemoria_Click(object sender, RoutedEventArgs e)
{

}

private void LiberaMemoria_Click(object sender, RoutedEventArgs e)
{

}

Creamos una colección de Bytes para cargar en memoria:

List<Byte[]> _memoria;

En el primer botón añadimos 10MB al uso de memoria cada vez que sea pulsado. En el segundo, limpiamos la colección y llamamos el recolector de basura:

private void AumentaMemoria_Click(object sender, RoutedEventArgs e)
{
     _memoria.Add(new Byte[1024 * 1024 * 10]);
}

private void LiberaMemoria_Click(object sender, RoutedEventArgs e)
{
     _memoria.Clear();
     GC.Collect();
}

Hasta aqui todo lo necesario para poder probar la memoria, podemos aumentarla y liberarla. Sin embargo, no tenemos ahora mismo posibilidad de saber que consumo esta realizando la aplicación. Vamos a añadir en nuestra interfaz un TextBlock donde mostrar la información relacionada con el uso de memoria:

<TextBlock Name="Data" />

Vamos a crear un método que actualice el texto del TextBlock anterior con la información relacionada con la memoria. Dentro del método usaremos la API DeviceStatus para acceder a ciertas propiedades relacionadas con la memoria. Las propiedades son:

private void ActualizarDatos()
{
     Data.Text = String.Format(@"
     Actual: {0}MB
     Pico máximo: {1}MB
     Límite de uso: {2}MB
     Total dispositivo: {3}MB",
     (DeviceStatus.ApplicationCurrentMemoryUsage / 1000000).ToString(CultureInfo.InvariantCulture),
     (DeviceStatus.ApplicationPeakMemoryUsage / 1000000).ToString(CultureInfo.InvariantCulture),
     (DeviceStatus.ApplicationMemoryUsageLimit / 1000000).ToString(CultureInfo.InvariantCulture),
     (DeviceStatus.DeviceTotalMemory / 1000000).ToString(CultureInfo.InvariantCulture));
}

Para finalizar llamaremos al método en los clic de los botones para actualizar los valores en pantalla cada vez que pulsemos uno de ellos:

ActualizarDatos();
Uso de memoria

Uso de memoria

Sin duda una forma sencilla para poder consultar el uso de memoria. Sin embargo, no es práctico en nuestras aplicaciones mostrar la información en pantalla. Para solventar esa situación, podemos realizar un sencillo Helper, llamado MemoryHelper, que contenga un método que obtendrá la misma información cada X segundos y las mostrará en la ventana de Output de Visual Studio:

public static void GetMemoryData(int seconds)
{
     _timer = new Timer(state =>
     {
          string result = string.Empty;
          result += String.Format(@"
          Fecha: {0}
          Actual: {1}MB
          Pico máximo: {2}MB
          Límite de uso: {3}MB
          Total dispositivo: {4}MB",
          DateTime.Now.ToLongTimeString(),
          (DeviceStatus.ApplicationCurrentMemoryUsage / 1000000).ToString(CultureInfo.InvariantCulture),
          (DeviceStatus.ApplicationPeakMemoryUsage / 1000000).ToString(CultureInfo.InvariantCulture),
          (DeviceStatus.ApplicationMemoryUsageLimit / 1000000).ToString(CultureInfo.InvariantCulture),
          (DeviceStatus.DeviceTotalMemory / 1000000).ToString(CultureInfo.InvariantCulture));

     Deployment.Current.Dispatcher.BeginInvoke(() => Debug.WriteLine(result));
     },
     null,
     TimeSpan.FromSeconds(seconds),
     TimeSpan.FromSeconds(seconds));
}
Ejemplo OutOfMemory 02

Resultados en la ventana de depuración

Podéis descargar el ejemplo a continuación:

Más información

[Tips and Tricks] Windows Phone. Aumentar la cantidad de memoria a utilizar por nuestras Apps.

Uso de memoria en Windows Phone 8

Con la maduración del mercado con respecto a Windows Phone, contamos con una variedad de dispositivos con distintas características. Una de las características que de forma comun varía entre diferentes dispositivos es la memoria RAM. Contamos con dispositivos con 512MB, 1GB o 2GB de RAM. Para llegar a la mayor cantidad de usuarios posibles tenemos que adaptar nuestra aplicación para que funcione correctamente bajo cualquier circunstancia.

Límites de memoria

Los límites de uso de memoria son los siguientes:

Límites de memoria

Límites de memoria

El límite de memoria viene marcado por la memoria total del dispositivo. Contamos con tres categorías, teléfonos con memoria baja con 512MB como por ejemplo el Nokia Lumia 520, teléfonos con 1GB como por ejemplo el Nokia Lumia 925 y teléfonos con 2GB como el Nokia Lumia 1520.

En aplicaciones utilizando XAML los límites son 150MB en dispositivos de baja memoria, 300MB en dispositivos de 1GB y 2GB.

Sin embargo, si nuestra aplicación lo requiere podría llegar a aumentar el límite de consumo de memoria en 30MB en dispositivos de baja memoria, 80MB en dispositivos de 1GB y en 270MB en dispositivos de 2GB (por ahora el Nokia Lumia 1520, pensando en el uso de recursos de alta definición con pantallas de gran tamaño).

Aumentar la cantidad disponible

Por lo tanto, si nuestra aplicación requiere un mayor consumo de memoria podemos aumentar los límites. Bien, pero… ¿como?

Lo podemos hacer con facilidad modificando el archivo de manifiesto. Podemos definir una Capability que indique que nuestra aplicación requiere un mayor consumo de memoria.

Bastará con añadir:

<App>
     <FunctionalCapabilities>
          <FunctionalCapability Name="ID_FUNCCAP_EXTEND_MEM"/>
     </FunctionalCapabilities>
</App>

La entrada anterior permite establecer los límites en 180MB en dispositivos de baja memoria, 380MB en dispositivos de 1GB y 570MB en dispositivos de 2G.

Si por la naturaleza de nuestra aplicación es inviable su funcionamiento en dispositivos de baja memoria, podemos añadir otra Capability en el archivo de manifiesto para evitar que se pueda instalar en estos dispositivos (no aparecería en la Store la aplicación bajo un dispositivo de estas características). Debemos añadir:

<App>
     <Requirements>
          <Requirements Name="ID_REQ_MEMORY_300"/>
     </Requirements>
</App>

Más información