Empty an ArrayList or just create a new one and let the old one be garbage collected? [duplicate]

What are the advantages and disadvantages of emptying a collection (in my case its an ArrayList) vs creating a new one (and letting the garbage collector clear the old one).

Specifically, I have an ArrayList<Rectangle> called list. When a certain condition occurs, I need to empty list and refill it with other contents. Should I call list.clear() or just make a new ArrayList<Rectangle> and let the old one be garbage collected? What are the pros and cons of each approach?


The advantage of recycling an ArrayList (e.g. by calling clear) is that you avoid the overhead of allocating a new one, and the cost of growing it ... if you didn't provide a good initialCapacity hint.

The disadvantages of recycling an ArrayList include the following:

  • The clear() method has to assign null to each (used) slot in the ArrayLists backing array.

  • The clear() does not resize the backing array to release memory. So if you repeatedly fill and clear a list, it will end up (permanently) using enough memory to represent the largest list that it encounters. In other word, you have increased the memory footprint. You can combat that by calling trimToSize(), but that creates a garbage object, etcetera1.

  • There are locality and cross-generational issues that could affect performance. When you repeatedly recycle an ArrayList, the object and its backing array are likely to be tenured. That means that:

    • The list objects and the objects representing list elements are likely to be in different areas of the heap, potentially increasing TLB misses and page traffic, especially at GC time.

    • Assignment of (young generation) references into the (tenured) list's backing array are likely to incur write barrier overheads ... depending on the GC implementation.

It is not possible to accurately model the performance trade-offs for a real-life application. There are just too many variables. However, the "received wisdom" is that recycling is NOT normally a good idea if you have plenty of memory2 and a half-decent garbage collector.

It is also worth noting that a modern JVM can allocate objects very efficiently. It merely needs to update to the heap's "free" pointer and write 2 or 3 object header words. The zeroing of memory is done by the GC ... and besides the work in doing that is roughly equivalent to the work that clear() does to null out references in the list that is being recycled.


1 - It would be better for performance to create a new ArrayList than to call clear() followed by trimToSize(...). With the latter you get both the garbage collection overheads AND the overheads of superfluous nulling.

2 - A copying collector is more efficient if the proportion of garbage objects to non-garbage objects is high. If you analyse the way that this kind of collector works, the costs are almost all incurred in finding and copying reachable objects. The only thing that needs to be done to garbage objects is to block-zero-write the evacuated "from" space ready for allocation of new objects.


My advice would be NOT to recycle ArrayList objects unless you have a demonstrable need to minimize the (garbage) object creation rate; e.g. because it is the only option you have for reducing (harmful) GC pauses.

All things being equal, on a modern Hotspot JVM my understanding is that you will get best performance by doing the following:

  • Allocating new ArrayList objects rather than recycling.
  • Use accurate initialSize hints when you allocate the list objects. It is better to slightly overestimate than slightly underestimate.

You keep the container and call clear when you would like to reduce the load on GC: clear() nulls out all the references inside the array, but does not make the array eligible for reclaiming by the garbage collector. This may speed up future inserts, because the array inside ArrayList does not need to grow. This approach is especially advantageous when the data that you plan to add to the container has roughly the same size as you clearing out.

In addition, you may need to use clear when other objects hold a reference to the array that you are about to clear.

Releasing the container and creating a new one makes sense when the size of the new data may be different from what was there before. Of course you can achieve a similar effect by calling clear() in combination with trimToSize().


As interesting points were already written, you can think about it even one level deeper.

I've haven't realized it than I read article about disruptor pattern, see How does LMAX's disruptor pattern work?

It's possible to not only to reuse underlying collection, you can reuse also entities within the collection.

E.g. suppose producer and consumer use-case. Producer can fill data into the same (cyclic) array over and over again and even use same entities. Just clear properties, internal state, and fill it's own.

It's one level better solution in the point of GC view. But it's obviously special case not useful for every problem.