Android Comprensión de tamaños de montón

Soy bastante nuevo en el desarrollo de Android y parece que no entiendo la excepción Java Out of Memory. Sé que significa que mi aplicación ha superado el presupuesto de VM, pero después de buscar en Google esto muchas veces, todavía no entiendo este concepto. Me temo que mi aplicación utiliza demasiada memoria porque tengo seis selectores de botones por pantalla con dos mapas de bits para cada selector, que son alrededor de 20 kb cada uno de acuerdo con la pestaña de propiedades. En mi rooteado G2x, configuré el presupuesto de VM en 12mb, reinicié mi teléfono y ejecuté mi aplicación sin ningún problema. Estoy desentrañando dibujables en cada onDestroy () y sugiero que el GC también se ejecute aquí. Después de usar la aplicación por un tiempo en el emulador, hago clic en “Causa GC” en mi pantalla DDMS y los resultados son ID = 1, Heap Size 6.133 MB, Asignado 2.895MB, Free 3.238 MB,% Used 47.20, # Objects 52,623.

Aquí es donde no entiendo lo que está sucediendo, mi emulador está configurado en 24MB de VM. ¿Dónde está ese número? El verdadero problema que tengo es que si configuro el emulador en 16 MB de VM, mi aplicación se bloquea en la segunda actividad con la excepción de Memoria agotada. ¿Cómo es que no se cuelga en mi teléfono con la VM configurada en 12 MB o en mi viejo teléfono HTC Magic con 12 MB de inventario de VM? ¿Ustedes también piensan que mi aplicación está ocupando demasiada memoria? No tengo idea si esos números de DDMS son buenos o no. Gracias por tu tiempo.

En cuanto a mi código, tengo todas las imágenes especificadas en los diseños XML. No hago nada programáticamente con ellas, excepto para agregar oyentes a ellas. Encontré este código aquí y lo agregué a cada actividad que tengo …

@Override protected void onDestroy() { super.onDestroy(); unbindDrawables(findViewById(R.id.myRootLayout)); System.gc(); } private void unbindDrawables(View view) { if (view.getBackground() != null) { view.getBackground().setCallback(null); } if (view instanceof ViewGroup && !(view instanceof AdapterView)) { for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { unbindDrawables(((ViewGroup) view).getChildAt(i)); } ((ViewGroup) view).removeAllViews(); } } 

De lo contrario, todo lo que hago es agregar OnClickListeners a los botones que tienen los fondos PNG. Me gustaría aprender cómo especificar los fondos de los botones de forma programática, pero necesito que las funciones del selector estén centradas, al presionar, no enfocadas, pero presionadas, etc., para que los fondos de los botones cambien según la interacción del usuario. He revisado los documentos acerca de esto, pero parece abrumador, es por eso que pensé que comenzaría aquí con los conceptos básicos de la administración de Heaps y me abriría camino hasta especificar selectores en el código. Esto puede no tener sentido, pero ¿hay una cantidad “sana” de asignación de memoria que una aplicación podría asignar sin acercarse a la excepción de Memoria agotada? Por ejemplo, si una aplicación asignó 6MB, debería estar bien, pero 8 MB la impulsarían, ¿hay límites como ese en la asignación de memoria? Gracias de nuevo Alex Lockwood por su respuesta. Voy a leerla y volver a leerla hasta que esto tenga sentido para mí.

Cuando configura el presupuesto de VM en su emulador / dispositivo, lo que está haciendo le dice al montón el tamaño máximo que está permitido. En tiempo de ejecución, el almacenamiento crece de forma dinámica a medida que la VM Dalvik solicita la memoria del sistema desde el sistema operativo. La máquina virtual de Dalvik normalmente comienza asignando un montón relativamente pequeño. Luego, después de ejecutar cada GC, se comprueba para ver cuánta memoria Heap libre hay. Si la proporción de montón libre a montón total es demasiado pequeña, la VM Dalvik agregará más memoria al montón (hasta el tamaño de montón máximo configurado).

Una vez dicho esto, la razón por la que no está viendo “24 mb” en su pantalla DDMS es porque el montón no ha crecido hasta su tamaño máximo. Esto permite a Android hacer un buen uso de la ya pequeña cantidad de memoria que está disponible en los dispositivos portátiles.

En cuanto a por qué su aplicación se bloquea en el emulador y no en su teléfono, parece extraño (¿está seguro de que los números son correctos?). Sin embargo, debe tener en cuenta que la memoria se gestiona de forma dinámica y que la utilización total de la memoria se determina en función de una serie de factores externos (la velocidad / frecuencia con la que se realiza la recolección de basura, etc.).

Finalmente, por las razones que mencioné anteriormente, sería difícil decir con certeza qué tan bien administra su aplicación la memoria en función de la única línea de información que proporcionó anteriormente. Realmente necesitaríamos ver algo de tu código. OutOfMemoryError embargo, definitivamente vale la pena preocuparse por OutOfMemoryError , así que definitivamente consideraré el uso de la memoria de su aplicación. Una cosa que podría considerar es muestrear sus imágenes de bitmap en tiempo de ejecución con llamadas a inSampleSize usando la clase BitmapFactory . Esto puede ayudar a reducir la cantidad de memoria requerida para cargar sus mapas de bits dibujables. O eso o podrías reducir la resolución de tus drawables (aunque 20 Kb cada uno me suena bien).

Incluso si su aplicación no alcanza el límite de almacenamiento dynamic de “24mb” (varía dentro de los dispositivos), es posible que aún tenga lockings, ya que Android demora un tiempo para hacer crecer el espacio de almacenamiento dynamic para su aplicación.

En mi situación, estaba creando y descargando varias imágenes en poco tiempo.

Muy a menudo OutOfMemoryError .

Parece que Android no fue lo suficientemente rápido como para hacer crecer el espacio de montón para mi aplicación.

Creo que resolví este problema usando la configuración de gran largeHeap en el archivo Manifiesto. Con esa configuración, Android deja más memoria libre cada vez que crece el montón, minimizando la posibilidad de alcanzar el límite actual.

No utilizo el límite de 24 mb, pero esta gran largeHeap fue bastante útil.

Solo necesita establecer largeHeap="true" en la etiqueta de la aplicación de su AndroidManifest.xml

  

Aún así, asegúrese de tener cuidado cuando se trata de imágenes, como aconseja @Alex Lockwood.