Hay dos formas de pensar en su frase "tamaño de almacenamiento dinámico de aplicación disponible":
¿Cuánto montón puede usar mi aplicación antes de que se active un error grave? Y
¿Cuánto montón debería usar mi aplicación, dadas las limitaciones de la versión del sistema operativo Android y el hardware del dispositivo del usuario?
Hay un método diferente para determinar cada uno de los anteriores.
Para el artículo 1 anterior: maxMemory()
que se puede invocar (por ejemplo, en el onCreate()
método de su actividad principal ) de la siguiente manera:
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));
Este método le indica cuántos bytes totales de almacenamiento dinámico puede usar su aplicación .
Para el artículo 2 anterior: getMemoryClass()
que se puede invocar de la siguiente manera:
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));
Este método le indica aproximadamente cuántos megabytes de almacenamiento dinámico debe usar su aplicación si quiere respetar adecuadamente los límites del dispositivo actual y los derechos de otras aplicaciones para ejecutarse sin ser forzados repetidamente al ciclo onStop()
/ onResume()
ya que son groseramente se quedó sin memoria mientras su aplicación de elefante se bañaba en el jacuzzi de Android.
Esta distinción no está claramente documentada, hasta donde yo sé, pero he probado esta hipótesis en cinco dispositivos Android diferentes (ver más abajo) y he confirmado para mi propia satisfacción que esta es una interpretación correcta.
Para una versión estándar de Android, maxMemory()
generalmente devolverá aproximadamente la misma cantidad de megabytes que se indican getMemoryClass()
(es decir, aproximadamente un millón de veces el último valor).
La única situación (de la que tengo conocimiento) en la que los dos métodos pueden divergir es en un dispositivo rooteado que ejecuta una versión de Android como CyanogenMod, que permite al usuario seleccionar manualmente qué tan grande debe permitirse un tamaño de almacenamiento dinámico para cada aplicación. En CM, por ejemplo, esta opción aparece en "Configuración de CyanogenMod" / "Rendimiento" / "Tamaño de almacenamiento dinámico de VM".
NOTA: TENGA EN CUENTA QUE LA CONFIGURACIÓN DE ESTE VALOR MANUALMENTE PUEDE MENSAJAR SU SISTEMA, ESPECIALMENTE si selecciona un valor más pequeño de lo normal para su dispositivo.
Aquí están los resultados de mi prueba que muestran los valores devueltos por maxMemory()
y getMemoryClass()
para cuatro dispositivos diferentes que ejecutan CyanogenMod, utilizando dos valores de almacenamiento dinámico diferentes (configurados manualmente) para cada uno:
- G1:
- Con VM Heap Size establecido en 16MB:
- maxMemory: 16777216
- getMemoryClass: 16
- Con VM Heap Size establecido en 24MB:
- maxMemory: 25165824
- getMemoryClass: 16
- Moto Droid:
- Con VM Heap Size establecido en 24MB:
- maxMemory: 25165824
- getMemoryClass: 24
- Con VM Heap Size establecido en 16MB:
- maxMemory: 16777216
- getMemoryClass: 24
- Nexus One:
- Con el tamaño de VM Heap establecido en 32 MB:
- maxMemory: 33554432
- getMemoryClass: 32
- Con el tamaño de VM Heap establecido en 24 MB:
- maxMemory: 25165824
- getMemoryClass: 32
- Viewsonic GTab:
- Con VM Heap Size establecido en 32:
- maxMemory: 33554432
- getMemoryClass: 32
- Con VM Heap Size establecido en 64:
- maxMemory: 67108864
- getMemoryClass: 32
Además de lo anterior, probé en una tableta Novo7 Paladin con Ice Cream Sandwich. Esta era esencialmente una versión estándar de ICS, excepto que he rooteado la tableta a través de un proceso simple que no reemplaza todo el sistema operativo, y en particular no proporciona una interfaz que permita que el tamaño del montón se ajuste manualmente.
Para ese dispositivo, aquí están los resultados:
- Novo7
- maxMemory: 62914560
- getMemoryClass: 60
También (por Kishore en un comentario a continuación):
- HTC uno X
- maxMemory: 67108864
- getMemoryClass: 64
Y (según el comentario de akauppi):
- Samsung Galaxy Core Plus
- maxMemory: (no especificado en el comentario)
- getMemoryClass: 48
- largeMemoryClass: 128
Por un comentario de cmcromance:
- Galaxy S3 (Jelly Bean) montón grande
- maxMemory: 268435456
- getMemoryClass: 64
Y (según los comentarios del tencent):
- LG Nexus 5 (4.4.3) normal
- maxMemory: 201326592
- getMemoryClass: 192
- LG Nexus 5 (4.4.3) montón grande
- maxMemory: 536870912
- getMemoryClass: 192
- Galaxy Nexus (4.3) normal
- maxMemory: 100663296
- getMemoryClass: 96
- Galaxy Nexus (4.3) montón grande
- maxMemory: 268435456
- getMemoryClass: 96
- Galaxy S4 Play Store Edition (4.4.2) normal
- maxMemory: 201326592
- getMemoryClass: 192
- Galaxy S4 Play Store Edition (4.4.2) montón grande
- maxMemory: 536870912
- getMemoryClass: 192
Otros dispositivos
- Huawei Nexus 6P (6.0.1) normal
- maxMemory: 201326592
- getMemoryClass: 192
No he probado estos dos métodos con la opción de manifiesto especial android: largeHeap = "true" disponible desde Honeycomb, pero gracias a cmcromance y tencent tenemos algunos valores de muestra de largeHeap, como se informó anteriormente.
Mi expectativa (que parece estar respaldada por los números grandes de Heap anteriores) sería que esta opción tendría un efecto similar a la configuración manual del montón a través de un sistema operativo rooteado, es decir, aumentaría el valor de maxMemory()
dejarlo getMemoryClass()
solo. Hay otro método, getLargeMemoryClass (), que indica la cantidad de memoria permitida para una aplicación que usa la configuración largeHeap. La documentación de getLargeMemoryClass () establece que "la mayoría de las aplicaciones no deberían necesitar esta cantidad de memoria y, en cambio, deberían permanecer con el límite getMemoryClass ()".
Si lo he adivinado correctamente, usar esa opción tendría los mismos beneficios (y peligros) que usaría el espacio disponible por un usuario que ha aumentado el montón a través de un sistema operativo rooteado (es decir, si su aplicación usa la memoria adicional, probablemente no jugará tan bien con cualquier otra aplicación que el usuario esté ejecutando al mismo tiempo).
Tenga en cuenta que la clase de memoria aparentemente no necesita ser un múltiplo de 8 MB.
Podemos ver de lo anterior que el getMemoryClass()
resultado no cambia para una configuración de dispositivo / SO dada, mientras que el valor maxMemory () cambia cuando el usuario configura el montón de manera diferente.
Mi propia experiencia práctica es que en el G1 (que tiene una clase de memoria de 16), si selecciono manualmente 24 MB como tamaño de almacenamiento dinámico, puedo ejecutarlo sin errores incluso cuando mi uso de memoria puede aumentar a 20 MB (presumiblemente podría ir tan alto como 24 MB, aunque no he probado esto). Pero otras aplicaciones similares de gran tamaño pueden ser borradas de la memoria como resultado de la fragilidad de mi propia aplicación. Y, por el contrario, mi aplicación puede enjuagarse de la memoria si el usuario pone en primer plano estas otras aplicaciones de alto mantenimiento.
Por lo tanto, no puede superar la cantidad de memoria especificada por maxMemory()
. Y, debe intentar mantenerse dentro de los límites especificados por getMemoryClass()
. Una forma de hacerlo, si todo lo demás falla, podría ser limitar la funcionalidad de dichos dispositivos de manera que conserve la memoria.
Finalmente, si planea superar el número de megabytes especificado getMemoryClass()
, mi consejo sería trabajar mucho y duro para guardar y restaurar el estado de su aplicación, de modo que la experiencia del usuario sea prácticamente ininterrumpida si ocurre un onStop()
/ onResume()
ciclo.
En mi caso, por razones de rendimiento, estoy limitando mi aplicación a dispositivos que ejecutan 2.2 y superiores, y eso significa que casi todos los dispositivos que ejecutan mi aplicación tendrán una clase de memoria de 24 o superior. Por lo tanto, puedo diseñar para ocupar hasta 20 MB de almacenamiento dinámico y sentirme bastante seguro de que mi aplicación funcionará bien con las otras aplicaciones que el usuario puede estar ejecutando al mismo tiempo.
Pero siempre habrá algunos usuarios rooteados que hayan cargado una versión 2.2 o superior de Android en un dispositivo anterior (por ejemplo, un G1). Cuando encuentre una configuración de este tipo, idealmente, debería reducir el uso de su memoria, incluso si maxMemory()
le dice que puede ir mucho más allá de los 16 MB que getMemoryClass()
le indican que debe apuntar. Y si no se puede garantizar de manera fiable que su aplicación va a vivir dentro de ese presupuesto, entonces por lo menos asegurarse de que onStop()
/ onResume()
funciona a la perfección.
getMemoryClass()
, según lo indicado anteriormente por Diane Hackborn (hackbod), solo está disponible para volver al nivel 5 de API (Android 2.0), por lo que, como aconseja, puede asumir que el hardware físico de cualquier dispositivo que ejecute una versión anterior del sistema operativo está diseñado para soportar de manera óptima aplicaciones que ocupan un espacio dinámico de no más de 16 MB.
Por el contrario, maxMemory()
según la documentación, está disponible toda la parte trasera manera de nivel 1. API maxMemory()
, en una versión pre-2.0, probablemente devolver un valor de 16 MB, pero yo hago ver que en mis (mucho más tarde) versiones de CyanogenMod del usuario puede seleccionar un valor de almacenamiento dinámico tan bajo como 12 MB, lo que presumiblemente daría como resultado un límite de almacenamiento dinámico más bajo, por lo que le sugiero que continúe probando el maxMemory()
valor, incluso para versiones del sistema operativo anteriores a 2.0. Es posible que incluso deba negarse a ejecutar en el improbable caso de que este valor se establezca incluso por debajo de 16 MB, si necesita tener más de lo que se maxMemory()
indica.