Does this form of memory management make sense at all in Java?
In the life-cycle of my application, I have to re-create an ArrayList that contains other ArrayLists of objects (reading them from storage). The ArrayList is always assigned to the same data member in a class, essentially leaving the older ArrayList-of-ArrayLists dangling (unreference-able or 开发者_开发问答inaccessible).
My understanding is that, unlike in C++, this doesn't result in a memory leak because the system knows when an object becomes unreference-able and frees the memory when/as it sees fit.
Still, old habits are hard to overcome and I am almost instinctively drawn to "help" the system by doing some cleanup myself before re-creating that ArrayList-of-ArrayLists:
for (InnerArray aList : outerArray)
aList.clear();
outerArray.clear();
My questions:
- Is this redundant?
- Am I doing more harm than good?
- Is this good in any way?
- Why?
It is redundant. You are not helping those objects get freed, because garbage collection will already determine them to be unreachable. You can't make them more unreachable than they already are. So, you waste a little bit of processing time on something that accomplishes nothing.
The main problem, though, is that you are confusing other developers who will be wondering why you're clearing that array. They may waste their time trying to figure out why you were doing that, if there's some hidden reason that they didn't see at first.
A similar problem that C++ developers tend to have with Java code is making finalizers; in Java you almost never want to do this, as finalizers add an additional cost to garbage collection and they aren't a reliable way to free resources because they may not get called for a long time, or ever.
- yup - Honestly I just don't get it. if you don't need an object anymore just make sure that you cannot access it anymore and you're good!
- yup - invoking might use processing power, garbage collection would probably use less to get rid of an object. It might also be confusing as Nate suggested.
- nope - I don't see anything good, sorry.
- See above and welcome to Java! You can concentrate on the fun stuff now :)
P.S. I'm not sure about what I'm going to say now, but the clear()
function might remove elements from an ArrayList
just by making sure that you cannot access them anymore through the ArrayList
variable. Probably it won't 'destroy' them but it will just make them eligible for garbage collection. It would be nice to know how that function is implemented...
P.P.S. You might be tempted to invoke GC yourself, don't do it! See related question.
EDIT:
Here is the clear()
from ArrayList
:
public void clear()
{
if (size > 0)
{
modCount++;
// Allow for garbage collection.
Arrays.fill(data, 0, size, null);
size = 0;
}
}
1) Is this redundant?
Yes.
2) Am I doing more harm than good?
Yes.
3) Is this good in any way?
No.
4) Why?
Calling clear()
on an ArrayList
changes the list's size
field and then carefully assigns null
to the elements of its backing array that that have just become invalid. The code of clear()
needs to do this because the references in those elements could cause other objects to remain reachable; i.e. leak memory.
However, when an ArrayList
becomes unreachable, the garbage collector won't ever again look at any of the elements of the backing array. The GC's marking process only traverses the reachable objects, and the reclamation process doesn't look at the contents of garbage objects / arrays.
So, basically, calling clear()
on an object that it about to become unreachable is a total waste of CPU cycles and memory / VM bandwidth. (And of course it is redundant code that the next guy is going to scratch his head about ...)
In fact, it is even debatable whether calling clear
and then reusing a list is a good idea at all:
Calling
clear
doesn't release / resize the backing array, so you could be left with a huge backing array for a list whose size is usually small.It is not inconceivable that the garbage collector can free a large enough array and allocate a new one of the same size faster than
clear()
can do its job. (For a start, the GC can use multiple processors, where a call toclear()
will run on one thread.)
Is there a scenario that actually justifies calling clear()?
The only scenario where its is absolutely necessary to clear/reuse a list is when something else references that particular list and you can't update the list references.
There may also be benefit in clearing / reusing lists on platform with constrained memory and/or a slow GC. However, I wouldn't attempt this "optimization" unless I had STRONG evidence that this was a problem. (This kind of optimization makes your code more complicated, and can lead to performance problems of its own if it is done incorrectly.)
精彩评论