Cuerdas y gestión de memoria

Me cuesta mucho entender lo que está pasando con las cadenas y la gestión de la memoria en Android (Java).

Para simplificar, eche un vistazo a esta sencilla pieza de código:

public void createArray(){ String s = ""; String foo = "foo"; String lorem = "Lorem ipsum ad his scripta blandit partiendo, eum fastidii accumsan euripidis in, eum liber hendrerit an."; ArrayList<Item> array = new ArrayList<Item>(); for( int i=0; i<20000; i++ ){ s = foo.replace("foo", lorem); array.add( new Item(s) ); } System.gc(); } private class Item{ String name; public Item(String name){ this.name = name; } } 

Si se ejecuta, createArray asignará más de 5Mb en la memoria. Incluso con la instrucción System.gc() , la memoria no se desasignará después del bucle.

Ahora, si reemplazamos s = foo.replace("foo", lorem); Con s = lorem; , La memoria asignada sólo aumentará en 0.5Mb.

Necesito entender lo que está pasando para mejorar el rendimiento de mi aplicación.

¿Puede alguien explicar cómo debo reemplazar las cuerdas en un caso como este? ¿Y por qué System.gc() no desasigna la memoria?

Gracias.

ACTUALIZACIÓN :

Gracias por las respuestas, ahora entiendo que System.gc() es sólo una pista.

Para aclarar la otra pregunta (la importante):

¿Cómo puedo generar dinámicamente 20000 cadenas ("foo1", "foo2" … "foo20000") agregarlos a la ArrayList y no quedan sin memoria? Si estas 20000 cadenas eran estáticas no asignarían más de 0.5Mb en memoria. Además, si s = foo.replace("foo", lorem) crea una cadena nueva, ¿por qué mi función asigna 5Mb que es 10 veces más memoria? ¿No debería ser alrededor de 1Mb?

(Ya estoy pensando en una solución, pero quiero estar seguro de que no hay manera de generar las cadenas dinámicamente sin utilizar esta enorme cantidad de memoria)

replace está generando un nuevo objeto String cada vez que se llama, ya que las cadenas en Java son inmutables y por lo tanto las modificaciones no se pueden hacer "ìn-place". Además, agrega esa String a una ArrayList que contendrá una referencia al nuevo objeto, evitando que se recopile.

Debido a que String es inmutable, llamar a foo.replace("foo", lorem) creará una nueva String cada vez. En el ejemplo en el que simplemente establece s = lorem , no se crea ninguna nueva String .

Además, System.gc () es simplemente una recomendación a la VM, y de ninguna manera garantiza una recolección de basura. No hay nada que puedas hacer para forzar una recolección de basura. (Aparte de usar toda la memoria disponible que sea)

System.gc () es una pista para que el recolector de basura ejecute de nuevo, cuando tiene el tiempo.

Dicho esto, el recolector de basura sólo recoge objetos no referenciados, y todas las cadenas que generó todavía están siendo retenidas por la array objetos. Es totalmente posible que usted puede agregar las líneas después de System.gc()

 for (String item : array) { System.out.println(item); } 

Lo que habría demostrado la sabiduría del recolector de basura en no destruir las cuerdas.

En el caso de que tenga alguna verdadera necesidad de reutilizar una cadena, puede intercambiar ciclos de CPU para una huella de memoria posiblemente menor con los métodos internos de cadena (que escanearán cadenas asignadas para duplicados y devolverán una referencia a la única cadena guardada si se encuentra.

Podría argumentar que en su caso la sugerencia de recolector de basura podría invocar técnicas de optimización de tiempo de compilación para darse cuenta de que la matriz no se está utilizando en sentido descendente y, por tanto, actúa para destruir las cadenas antes de que normalmente se desreferenciaran al final del programa; Sin embargo, agregaría efectos secundarios que parecerían bastante extraños en algunos entornos de ejecución (como sesiones de depuración).

Al final, no es posible realizar con precisión la reflexión, el paso de código, compilar la vinculación al código fuente y varios tipos de reflexión con tal optimización exótica de tiempo de compilación. Dicho esto, Java se optimiza bastante bien teniendo en cuenta cuántas características obtienes fuera de la caja.

Tenga en cuenta que System.gc() no obliga al recolector de basura a ejecutarse. Es simplemente una pista que le gustaría que se ejecute en algún momento en el futuro.

  • reutilizar las mismas instancias de Diálogos
  • ¿Qué es lo que hace Bitmap # recycle () en Android Honeycomb?
  • Liberar mapas de bits de android.view.GLES20DisplayList
  • Cómo corregir este error: java.lang.OutOfMemoryError
  • Cómo obtener FileInputStream para archivos de memoria interna en Android? El archivo está en mi carpeta personalizada hecha en el espacio de la aplicación
  • Herramientas de análisis de memoria / rendimiento para Android
  • Fuga de memoria MediaControllerCompat
  • Float o doble?
  • Cómo evitar createBitmap () bloqueo en android
  • Cómo borrar la vista creada dinámicamente de la memoria?
  • Razones por las que mi aplicación Android se bloquea en mi teléfono de forma consistente, pero no en mi emulador
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.