¿Cuál es la cantidad máxima de RAM que puede usar una aplicación?


145

Tengo mucha curiosidad acerca de esta pregunta sobre la gestión de memoria del sistema operativo Android, así que espero una respuesta bastante detallada sobre ese tema.

Lo que me gustaría saber:

  • ¿Cuál es la cantidad máxima de memoria (en megabytes / como porcentaje de la RAM total) que puede usar una aplicación de Android (que no es una aplicación del sistema)?
  • ¿Hay alguna diferencia entre las versiones de Android ?
  • ¿Hay alguna diferencia con respecto al fabricante del dispositivo?

Y más importante:

  • ¿Qué se considera / de qué depende cuando se trata de que el sistema determine cuánta RAM puede usar una aplicación en tiempo de ejecución (suponiendo que el máximo de memoria por aplicación no sea un número estático)?

Lo que he escuchado hasta ahora (hasta 2013):

  • Los primeros dispositivos Android tenían un límite por aplicación de 16 MB
  • Más tarde, este límite aumentó a 24 MB o 32 MB

Lo que me da mucha curiosidad:

Ambos límites son muy bajos.

Recientemente descargué el Administrador de tareas de Android para verificar la RAM de mis dispositivos. Lo que he notado es que hay aplicaciones que usan alrededor de 40-50 megabytes de RAM, lo cual es obviamente más que el uso máximo de RAM mencionado, digamos 32 MB. Entonces, ¿cómo determina Android cuánta RAM puede usar una aplicación? ¿Cómo es posible que las aplicaciones excedan ese límite?

Además, noté que algunas aplicaciones de minas se bloquean (¿son asesinadas por el sistema?) Con una excepción OutOfMemoryException cuando se usan alrededor de 30-40 megabytes. Por otro lado, tengo aplicaciones que se ejecutan en mi teléfono con 100 MB y más después de un tiempo (probablemente debido a pérdidas de memoria) que no se bloquean ni se matan. Entonces , obviamente, también depende de la aplicación en sí cuando se trata de determinar cuánta RAM se puede ahorrar. ¿Cómo es esto posible? (Realicé mis pruebas con un HTC One S con 768 MB de RAM)

Descargo de responsabilidad: NO estoy afiliado a la aplicación Android Task Manager de ninguna manera.

Respuestas:


119

¿Cuál es la cantidad máxima de memoria (en megabytes / como porcentaje de la RAM total) que una aplicación de Android (que no es una aplicación del sistema) puede usar?

Eso varía según el dispositivo. getMemoryClass()onActivityManager le dará el valor para el dispositivo en el que se ejecuta su código.

¿Hay alguna diferencia entre las versiones de Android?

Sí, en la medida en que los requisitos del sistema operativo han aumentado a lo largo de los años, y los dispositivos tienen que ajustarse para adaptarse.

¿Existen diferencias con respecto al fabricante del dispositivo?

Sí, en la medida en que los fabricantes fabrican dispositivos, y el tamaño varía según el dispositivo.

¿Qué "factores secundarios" se tienen en cuenta a la hora de determinar cuánta RAM puede usar una aplicación?

No tengo idea de lo que significa "factores secundarios".

Los primeros dispositivos tenían un límite por aplicación de 16 MB; Los dispositivos posteriores aumentaron eso a 24 MB o 32 MB

Eso es correcto. La resolución de pantalla es un determinante significativo, ya que las resoluciones más grandes significan mapas de bits más grandes, por lo que las tabletas y los teléfonos de alta resolución tenderán a tener valores más altos todavía. Por ejemplo, verá dispositivos con montones de 48 MB, y no me sorprendería si hay valores más altos que eso.

¿Cómo es posible que las aplicaciones excedan ese límite?

Asume que el autor de esa aplicación sabe lo que está haciendo. Teniendo en cuenta que el uso de memoria de una aplicación es difícil de determinar para un ingeniero principal de Android , no asumiría que la aplicación en cuestión necesariamente proporciona resultados particularmente precisos.

Dicho esto, el código nativo (NDK) no está sujeto al límite de almacenamiento dinámico. Y, desde Android 3.0, las aplicaciones pueden solicitar un "montón grande", generalmente en el rango de cientos de MB, pero eso se considera una forma deficiente para la mayoría de las aplicaciones.

Además, noté que algunas aplicaciones mías se bloquean con una excepción OutOfMemoryException cuando se usan alrededor de 30-40 megabytes.

Tenga en cuenta que el recolector de basura de Android no es un recolector de basura de compactación. La excepción realmente debería ser CouldNotFindSufficientlyLargeBlockOfMemoryException, pero eso probablemente se consideró demasiado prolijo. OutOfMemoryExceptionsignifica que no pudo asignar su bloque solicitado , no que haya agotado por completo su montón.


No puedo entender sobre la mesa, tengo un móvil Xperia X que tiene una resolución de 1080 x 1920 que es de gran resolución, y otro dispositivo Samsung Tab 4 que tiene una resolución de 800 x 1280, por lo que requiere la misma ocupación de memoria ram, por favor, guíame porque el móvil viene con 3 GB de RAM y la pestaña viene con 1,5 GB de RAM, ¿entonces la tableta ocupa un gran ram debido a la gran pantalla?
Rahul Mandaliya

@RahulMandaliya: Lo siento, pero no entiendo su preocupación o lo que tiene que ver con esta pregunta. Es posible que desee abrir una pregunta de desbordamiento de pila por separado donde explique en detalle cuál es su preocupación.
CommonsWare

15

Es finales de 2018, por lo que las cosas han cambiado.

En primer lugar: ejecute su aplicación y abra la pestaña Android Profiler en Android Studio. Verá cuánta memoria consume, se sorprenderá pero puede asignar mucha RAM.

También aquí hay un gran artículo en documentos oficiales con instrucciones detalladas sobre cómo usar Memory Profiler que puede darle una visión en profundidad de su administración de memoria.

Pero en la mayoría de los casos, su Android Profiler habitual será suficiente para usted.

ingrese la descripción de la imagen aquí

Por lo general, una aplicación comienza con 50Mb de asignación de RAM, pero salta instantáneamente hasta 90Mb cuando comienza a cargar algunas fotos en la memoria. Cuando abres Activity con un ViewPager con fotos precargadas (3,5Mb cada una) puedes obtener 190Mb fácilmente en segundos.

Pero esto no significa que tenga problemas con la administración de la memoria.

El mejor consejo que puedo dar es seguir las pautas y las mejores prácticas, usar las mejores bibliotecas para cargar imágenes (Glide, Picasso) y estarás bien.


Pero si necesita adaptar algo y realmente necesita saber cuánta memoria puede asignar manualmente, puede obtener memoria libre total y calcular una porción predeterminada (en%) de ella. En mi caso, necesitaba almacenar en caché las fotos descifradas en la memoria, así que no necesito descifrarlas cada vez que el usuario se desliza por la lista.

Para este propósito, puede usar la clase LruCache lista para usar . Es una clase de caché que rastrea automáticamente la cantidad de memoria que asignan sus objetos (o la cantidad de instancias) y elimina la más antigua para mantener la reciente por su historial de uso. Aquí hay un gran tutorial sobre cómo usarlo.

En mi caso, creé 2 instancias de cachés: para pulgares y archivos adjuntos. Los hizo estáticos con acceso singleton para que estén disponibles globalmente en toda la aplicación.

clase de caché:

public class BitmapLruCache extends LruCache<Uri, byte[]> {

    private static final float CACHE_PART_FOR_THUMBS_PRC = 0.01f; // 1% (Nexus 5X - 5Mb)
    private static final float CACHE_PART_FOR_ATTACHMENTS_PRC = 0.03f;// 3% (Nexus 5X - 16Mb)
    private static BitmapLruCache thumbCacheInstance;
    private static BitmapLruCache attachmentCacheInstance;

public static synchronized BitmapLruCache getDecryptedThumbCacheInstance() {
    if (thumbCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_THUMBS_PRC);
    //L.log("creating BitmapLruCache for Thumb with size: " + cacheSize + " bytes");
        thumbCacheInstance = new BitmapLruCache(cacheSize);
        return thumbCacheInstance;
    } else {
        return thumbCacheInstance;
    }
}

public static synchronized BitmapLruCache getDecryptedAttachmentCacheInstance() {
    if (attachmentCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_ATTACHMENTS_PRC);
    //            L.log("creating BitmapLruCache for Attachment with size: " + cacheSize + " bytes");
        attachmentCacheInstance = new BitmapLruCache(cacheSize);
        return attachmentCacheInstance;
    } else {
        return attachmentCacheInstance;
    }
}

private BitmapLruCache(int maxSize) {
    super(maxSize);
}

public void addBitmap(Uri uri, byte[] bitmapBytes) {
    if (get(uri) == null && bitmapBytes != null)
        put(uri, bitmapBytes);
}

public byte[] getBitmap(Uri uri) {
    return get(uri);
}


@Override
protected int sizeOf(Uri uri, byte[] bitmapBytes) {
    // The cache size will be measured in bytes rather than number of items.
    return bitmapBytes.length;
}
}

Así es como calculo la RAM libre disponible y cuánto puedo extraer:

private static int getCacheSize(float partOfTotalFreeMemoryToUseAsCache){
    final long maxMemory = Runtime.getRuntime().maxMemory();
    //Use ... of available memory for List Notes thumb cache
    return (int) (maxMemory * partOfTotalFreeMemoryToUseAsCache);
}

Y así es como lo uso en Adaptadores para obtener la imagen en caché:

byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri);

y cómo lo configuré en caché en el hilo de fondo (AsyncTask regular):

BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes); 

Mi aplicación está dirigida a API 19+, por lo que los dispositivos no son viejos y estas porciones de RAM disponibles son lo suficientemente buenas para la caché en mi caso (1% y 3%).

Dato curioso: Android no tiene ninguna API u otros hacks para obtener la cantidad de memoria asignada a su aplicación, se calcula sobre la marcha en función de varios factores.


PD: Estoy usando un campo de clase estático para contener un caché, pero según las últimas directrices de Android, se recomienda usar el componente de arquitectura ViewModel para ese propósito.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.