2012-03-22 21 views
12

Estoy saliendo de error de memoria. Estoy trabajando en la aplicación de chat en vivo. Está funcionando bien, pero cuando ejecuto la aplicación de 1 a 2 horas en el dispositivo, el tamaño del almacenamiento dinámico aumenta y cuando llegó a 16 MB la aplicación comienza a colgarse y se bloquea después de un tiempo y muestra out of memory due to heap size porque el tamaño de almacenamiento dinámico resultante es mayor que asignado.Error de falta de memoria en Android debido al aumento del tamaño del montón

Estoy probando mi aplicación en HTC Explorer. En mi aplicación, la mayoría de las actividades usan hilo de fondo y para eso estoy usando Asnyc Task.

Recibo un error como el siguiente.

04-30 16:53:14.658: E/AndroidRuntime(5707): FATAL EXCEPTION: MagentoBackground 
04-30 16:53:14.658: E/AndroidRuntime(5707): java.lang.OutOfMemoryError: (Heap Size=20167KB, Allocated=16063KB, Bitmap Size=355KB) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.util.ByteArrayBuffer.<init>(ByteArrayBuffer.java:53) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.io.AbstractSessionInputBuffer.init(AbstractSessionInputBuffer.java:82) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:98) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:173) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:359) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) 
04-30 16:53:14.658: E/AndroidRuntime(5707):  at com.live2support.CustomHttpClient.executeHttpPost1(CustomHttpClient.java:163) 

¿Hay límite de tamaño de la pila? ¿Cómo puedo resolver mi problema?

+1

Publica un código. Supongo que está usando grandes mapas de bits dentro de la lista personalizada. – Venky

+0

... o a una gran variedad? –

+0

no estoy usando mapa de bits en mi aplicación.i Tengo algunas imágenes en la carpeta dibujable y las estoy usando solo que no son mucho más de 15 a 20 imágenes que tengo. – nikki

Respuesta

11

Su pregunta tiene dos partes:

1) ¿Cómo puedo determinar el tamaño de la pila en el dispositivo de prueba?

2) ¿Por qué mi aplicación excede el tamaño de mi pila?

Sobre la pregunta 1, se puede determinar el tamaño de la pila en el dispositivo de prueba directamente en el código llamando a:.

Runtime.getRuntime() MaxMemory();

Consulte this post para obtener información adicional sobre ese método, así como algunos ejemplos de tamaños de almacenamiento dinámico disponibles en varios dispositivos.

Además, si está ejecutando un dispositivo rooteado, puede haber una manera de establecer (y verificar) directamente el tamaño del almacenamiento dinámico a través de la interfaz. Por ejemplo, en las distintas versiones de Android de CyanogenMod, desde el menú Configuración, puede seleccionar "Configuración de CyanogenMod" y luego "Rendimiento" y luego "Tamaño de almacenamiento dinámico de la VM" y ver (y cambiar) directamente el tamaño del almacenamiento dinámico para su dispositivo . Tenga cuidado, ya que configurar el tamaño del montón demasiado pequeño puede hacer que su dispositivo se comporte mal o peor.

En relación con la pregunta 2: no ha proporcionado suficiente información para diagnosticar su problema específico y, en cualquier caso, hacer tal diagnóstico de segunda mano es, en el mejor de los casos, difícil. Su mejor apuesta para resolver este problema (y para aprender algo de valor duradero en el proceso) sería familiarizarse con algunas de las poderosas herramientas de análisis de memoria disponibles en Android (algunas de las cuales también están integradas en el Eclipse IDE). Utilizo estas herramientas de Eclipse, así que eso es lo que describiré a continuación.

Antes que nada, asegúrese de que su versión de Eclipse esté actualizada instalando la última versión de Eclipse (por ejemplo, Indigo).

A continuación, en Eclipse, seleccione Ayuda/Instalar nuevo software y haga clic en el menú desplegable en la parte superior y seleccione

"Indigo - http://download.eclipse.org/releases/indigo" 

A continuación, abra la categoría General herramientas de uso haciendo clic en el signo más junto a ella, y seleccione Memory Analyzer y también Memory Analyzer (Charts) [opcional]. Instala estas herramientas

A continuación, seleccione Ventana/Preferencias, y luego Android/DDMS, y seleccione la acción HPROF como "Abrir en Eclipse". Esto hará que cualquier archivo de volcado de almacenamiento HPROF que genere desde DDMS tenga el formato apropiado para Eclipse, y también hará que se abra automáticamente en el Analizador de memoria de Eclipse (que acaba de instalarse arriba).

Ahora, abra DDMS seleccionando Ventana/Abrir perspectiva/Otro/DDMS. Seleccione el ícono de Dispositivos (parece un teléfono) a la izquierda y arrastre la ventana resultante para que esté acoplada en algún lugar donde pueda verla fácilmente.

Asegúrese de que su dispositivo esté conectado a la PC a través de USB y de que su aplicación esté en funcionamiento.

En la pestaña Dispositivos que acaba de crear, seleccione el proceso de su aplicación en ejecución. Ejecute la aplicación hasta el punto en que haya ocupado suficiente memoria como para saber que se ha filtrado, pero no tanto que falle. Ahora, haga clic en el ícono del archivo de Dump HPROF en la pestaña de dispositivos. Después de un breve retraso, se le ofrecerá una selección de informes en su montón. Pruebe el Informe de Sospechosos de Fugas para comenzar. Este informe se abrirá en la herramienta de análisis de memoria. Te dice dónde está usando tu aplicación la memoria. Verifique los diversos tipos de objetos y vea si se ven hinchados en relación con la cantidad de datos que esperaría que requirieran; si es así, eso puede indicar una fuga.

Here es un buen tutorial que describe con más detalle cómo generar y explorar su montón utilizando DDMS y la herramienta Memory Analyzer.

Detrás en DDMS (o la perspectiva DDMS en Eclipse), puede seleccionar la pestaña Allocation Tracker mientras su dispositivo está conectado y luego su dispositivo de la pestaña de dispositivos y luego seleccionar el proceso de su aplicación de la lista para ese dispositivo . A continuación, en la pestaña Rastreador de asignaciones, haga clic en el botón Iniciar seguimiento y luego ejecute las operaciones relevantes de su aplicación (aquellas que sospecha que se están filtrando) y luego haga clic en el botón Obtener asignaciones y luego seleccione el botón Detener seguimiento.

Esto mostrará todas las asignaciones que se hayan producido mientras realizaba el seguimiento (hay límites para la cantidad que almacenará).Al hacer clic en cualquiera de estos, accederá a la pila en el momento de la asignación, y al hacer clic en cualquier parte de ese volcado de pila, accederá al código fuente que estuvo involucrado en la asignación.

Estas herramientas deberían darle una idea de lo que podría estar causando que su aplicación pierda memoria.

+0

thanks curl .............. ....... – nikki

1

El límite de tamaño de almacenamiento dinámico depende del dispositivo. En un dispositivo 2.x, espero que su límite sea 20 o 32 MB. Consulte Android heap size on different phones/devices and OS versions para obtener más información sobre los tamaños de montón.

Desde su rastro de pila, parece que com.live2support.CustomHttpClient.executeHttpPost1() es el centro de su problema.

+0

, ¿qué puedo hacer? – nikki

+0

cosas habituales. Probaría las cosas en este orden: 1. inspección visual del código. También puede agregar su función a esta pregunta en SO para que otros puedan verificarla. 2. paso por el código usando un depurador de nivel de fuente. 3. Use DDMS si 2 no funciona. http://developer.android.com/guide/developing/debugging/ddms.html – Sparky

7

Parece una pérdida de memoria clásica. Usted dice que utiliza AsyncTask para la conexión. Es muy fácil perder el contexto con un AsyncTask en los cambios de configuración (por ejemplo, rotación del dispositivo) cuando no se sabe cómo usarlo correctamente.

Lo primero - te recomiendo que ver esto: http://www.youtube.com/watch?v=_CruQY55HOk

Para comprobar si tiene una fuga de memoria de este tipo, girar el dispositivo y comprobar cómo se comporta el recolector de basura. Debería tener algo como GC_... freed 211K, 71% free 300K/1024K, external 0K/0K, paused 1ms+1ms en su LogCat casi cada vez que gira. Esté atento a los cambios en esta parte: 300K/1024K. Si no tiene pérdidas de memoria, la primera parte debería crecer y luego disminuir después de unos pocos GC. Si tiene una pérdida de memoria, crecerá y crecerá, hasta el punto de error OOM.

Si se asegura de que tiene una pérdida de memoria de esta manera, lo que debe hacer es instalar MAT para Eclipse, aprender a usarlo (con la película antes mencionada) y averiguar qué causa.

Mi apuesta personal sería una mala implementación de AsyncTask - ¿la desconectas de la Actividad destruida y la adjuntas a la nueva? Si no, comience a hacerlo (hay un excelente ejemplo de CommonsWare) o cambie a AsyncTaskLoader que lo hace por usted y generalmente es un gran reemplazo para AsyncTask (no solo para cargar cosas).

+0

También tuve un problema extraño con el error OOM que apareció solo cuando comencé mi aplicación desde el depurador. Cuando se inició normalmente con el ícono del iniciador, la pérdida de memoria no ocurrió: http://stackoverflow.com/questions/10305037/leaking-memory-with-actionbarsherlock –

0

Esto se puede hacer de dos maneras según su sistema operativo Android.

  1. Puede utilizar android:largeHeap="true" en la etiqueta de aplicación de Android manifestarse para pedir un tamaño de la pila más grande, pero esto no va a funcionar en cualquier dispositivo de nido de abeja previamente.
  2. En dispositivos pre 2.3, puede usar la clase VMRuntime, pero esto no funcionará en Gingerbread y superiores. Vea a continuación cómo hacerlo.
VMRuntime.getRuntime().setMinimumHeapSize(BIGGER_SIZE); 

Antes de ajustar los TamañoPila asegúrese de que ha introducido el tamaño adecuado que no afecte a otra aplicación o funcionalidad del sistema operativo. Antes de la configuración solo verifica el tamaño de la aplicación y luego configura el tamaño solo para completar tu trabajo. No use mucha memoria, de lo contrario, otras aplicaciones podrían afectar.

Referencia: http://dwij.co.in/increase-heap-size-of-android-application

4

Sólo añadir android:largeHeap="true" en la etiqueta de aplicación dentro de sus manifiestos.

+3

Si bien este código puede responder a la pregunta, proporcionar un contexto adicional sobre cómo y/o por qué resuelve el problema mejoraría el valor a largo plazo de la respuesta. – mech

Cuestiones relacionadas