¿Vaciar una ArrayList o simplemente crear una nueva y dejar que la anterior sea recogida de basura?

¿Cuáles son las ventajas y desventajas de vaciar una colección (en mi caso es una ArrayList) frente a crear una nueva (y dejar que el recolector de basura limpie la anterior).

Específicamente, tengo una list llamada ArrayList . Cuando se produce una determinada condición, necesito vaciar la list y volver a llenarla con otros contenidos. ¿Debo llamar a list.clear() o simplemente crear una nueva ArrayList y dejar que la anterior sea basura? ¿Cuáles son los pros y los contras de cada enfoque?

Guarde el contenedor y llame clear cargo cuando desee reducir la carga en GC: clear() anula todas las referencias dentro de la matriz, pero no hace que la matriz sea elegible para reclamar por el recolector de basura. Esto puede acelerar insertos futuros, porque la matriz dentro de ArrayList no necesita crecer. Este enfoque es especialmente ventajoso cuando los datos que planea agregar al contenedor tienen más o menos el mismo tamaño que se borran.

Además, puede necesitar clear cuando otros objetos contienen una referencia a la matriz que está a punto de borrar.

Liberar el contenedor y crear uno nuevo tiene sentido cuando el tamaño de los nuevos datos puede ser diferente de lo que estaba allí antes. Por supuesto, puede lograr un efecto similar llamando a clear() en combinación con trimToSize() .

La ventaja de reciclar una ArrayList (por ejemplo, llamando a clear ) es que evita la sobrecarga de asignar una nueva y el costo de hacerla crecer … si no proporcionó una buena pista de initialCapacity .

Las desventajas de reciclar una ArrayList incluyen lo siguiente:

  • El método clear() debe asignar null a cada ranura (utilizada) en la matriz de respaldo ArrayList .

  • El clear() no cambia el tamaño de la matriz de respaldo para liberar memoria. Por lo tanto, si llena y borra repetidamente una lista, terminará (permanentemente) usando suficiente memoria para representar la lista más grande que encuentre. En otras palabras, ha aumentado la huella de memoria. Puedes combatir eso llamando a trimToSize() … que crea un objeto de basura, etcétera.

  • Hay problemas locales y transgeneracionales que pueden afectar el rendimiento. Cuando recicla repetidamente una ArrayList , es probable que el objeto y su matriz de respaldo estén en posesión. Eso significa que:

    • Es probable que los objetos de lista y los objetos que representan elementos de lista se encuentren en diferentes áreas del almacenamiento dynamic, lo que puede boost el número de errores TLB y el tráfico de la página, especialmente en el momento del GC.

    • La asignación de referencias (generación joven) al conjunto de respaldo de la lista (tenured) probablemente incurrirá en gastos generales de barrera de escritura … dependiendo de la implementación del GC.


No es posible modelar con precisión las compensaciones de rendimiento para una aplicación de la vida real. Hay demasiadas variables. Sin embargo, la “sabiduría recibida” es que reciclar normalmente NO es una buena idea si tienes suficiente memoria 1 y un recolector de basura medio decente.

También vale la pena señalar que una JVM moderna puede asignar objetos de manera muy eficiente. Simplemente necesita actualizar al puntero “libre” del montón y escribir 2 o 3 palabras del encabezado del objeto. La puesta a cero de la memoria la realiza el GC … y además el trabajo al hacerlo es más o menos equivalente al trabajo que clear() hace para anular las referencias en la lista que se está reciclando.

1 – Un recolector de copias es más eficiente si la proporción de objetos de basura a objetos que no son basura es alta. Si analiza la forma en que funciona este tipo de coleccionista, casi todos incurren en costos para encontrar y copiar objetos alcanzables. Lo único que hay que hacer con los objetos de basura es bloquear-escribir cero el espacio “de” evacuado listo para la asignación de objetos nuevos.


Mi consejo sería NO reciclar objetos ArrayList menos que tenga una necesidad demostrable de minimizar la tasa de creación de objetos (basura); por ejemplo, porque es la única opción que tiene para reducir (nocivas) las pausas del GC.

En igualdad de condiciones, en una JVM Hotspot moderna, entiendo que obtendrás el mejor rendimiento haciendo lo siguiente:

  • Asignación de nuevos objetos ArrayList en lugar de reciclaje.
  • Use sugerencias precisas de initialSize cuando asigne los objetos de la lista. Es mejor sobreestimar ligeramente que subestimar ligeramente.

Como ya se escribieron puntos interesantes, puedes pensar incluso en un nivel más profundo.

No me he dado cuenta de lo que leí en el artículo sobre el patrón de interruptores. Consulte ¿Cómo funciona el patrón disruptivo de LMAX?

Es posible no solo reutilizar la colección subyacente, sino también reutilizar entidades dentro de la colección.

Por ejemplo, supongamos el caso de uso del productor y el consumidor. El productor puede completar los datos en la misma matriz (cíclica) una y otra vez e incluso usar las mismas entidades. Simplemente borre las propiedades, el estado interno y complételo.

Es una solución de un nivel mejor en el punto de vista de GC. Pero obviamente es un caso especial que no es útil para todos los problemas.

Realmente no importa …

Una implementación List.clear () establece las referencias de la matriz interna a null. Establecer de manera efectiva los objetos como basura recolectada si no hay más referencias.

Si su única preocupación es la memoria, no existe una diferencia real medible en ambos enfoques. Incluso en lo que respecta a la operación, la diferencia estará en las asignaciones de matriz (en operaciones de redimensionamiento) y en otras operaciones de ese tipo.

Pero aclararlo puede ser marginalmente mejor, aunque si crear una nueva lista es más legible, iría con eso.