Empty an ArrayList or just create a new one and let the old one be garbage collected?
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 assignnull
to each (used) slot in theArrayList
s 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 callingtrimToSize()
, 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()
.