views:

198

answers:

3

A little question regarding performance in a Java web app.

Let's assume I have a List<Rubrique> listRubriques with ten Rubrique objects.

A Rubrique contains one list of products (List<product> listProducts) and one list of clients (List<Client> listClients).

What exactly happens in memory if I do this:

listRubriques.clear(); listRubriques = null;

My point of view would be that, since listRubriques is empty, all my objects previously referenced by this list (including listProducts and listClients) will be garbage collected pretty soon. But since Collection in Java are a little bit tricky and since I have quite performance issues with my app i'm asking the question :)

edit : let's assume now that my Client object contains a List<Client>. Therefore, I have kind of a circular reference between my objects. What would happen then if my listRubrique is set to null? This time, my point of view would be that my Client objects will become "unreachable" and might create a memory leak?

+8  A: 

The actual Sun-implementation for Java copies from time to time all referenced/living objects. The space from which was copied can then be used again for memory allocation.

That said your examples damages actually performance. listRubriques.clear() is unneeded (except you hold somethere else a reference to it), because everything referenced by listRubrique is garbage the moment listRubriques is no longer referenced. listRubriques = null may also unneeded if the variable listRubriques go out of scope afterwards (possibly because it's a local variable and the method ends here).

Not only the call to clear is unneeded, as clear accesses the memory of the object that is afterwards no longer in use, the object is accessed and modern processors will put it into their cache. So a dead object is explicitly going to the processor-cache - some possibly more useful data will be overwritten for that operation.

This article is a good reference to get more informations about the Java Garbage collector.

EDIT: To react on the edit in the question: The Garbage collector (the implementation used by Sun at least) is starting from some root references and copies all objects it can reach from this references and that are referenced by the copied objects. So your circular referenced objects are garbage, as no 'outer' reference is pointing to them and the memory will be reclaimed in the garbage collection.

Mnementh
Careful: your first sentence describes the current implementation of the Sun JVM. It's not a statement that's true about Java generally. The rest of the answer seems to be applicable in general, 'though.
Joachim Sauer
Thanks for the hint, I changed the first sentence.
Mnementh
+1  A: 

If you have:

listRubriques = null;

and there are no other objects holding references to listRubriques or its containing objects, it's eligible for garbage collection. But there is no guarantee about when the JVM will actually run garbage collection on it and free memory. You can call:

System.gc();

to recommend to the JVM that you think running garbage collection at this time is a good idea. But even then, there is no guarantee.

Also having

listRubriques.clear();

before setting listRubriques to null is not necessary.

EDIT: To answer your question about circular references, JVMs are smart enough to figure out that the whole object graph is disconnected from any actively running code and the JVM will correctly determine that they are all eligible for garbage collection. This has always been true even in the bad old days of reference counting. Modern JVMs are just faster and more efficient. But they aren't garbage collecting any more objects than older JVMs.

Asaph
Regarding the clear before the null I did it simply to be sure that my object won't have any references anymore. But i'm ok it's a useless double check.I read that System.gc(); was useful in old java versions but is totally ignored nowadays, isn't it ?
Anth0
@Anth0: I haven't heard that and the J2SE docs for Java 6 make no mention of anything like that ( http://java.sun.com/javase/6/docs/api/java/lang/System.html#gc() ). For maximum portability, it's best not to make any assumptions about the JVM implementation your app will be running on. Check out this article from Sun for the truth about garbage collection: http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html
Asaph
Invoking System.gc() is usually awarded by newer VMs as well, although not guaranteed. If you request the GC to run, although it's not necessary, you are however potentially creating a performance problem and not solving one.
jarnbjo
@Asaph : Great thanks for your link. I've learned a lot ! And I'm gonna edit my question :)
Anth0
@Anth0: I've updated my answer. Don't worry about circular references. The JVM is and always has been smart enough to deal with that edge case. For a detailed discussion, read all of Section A.3.4 in the truth about garbage collection link I posted in my comment above.
Asaph
+1  A: 

"Pretty soon" is a rather vague specification, but the garbage collector is probably not as swift as you seem to expect. When the objects actually will be collected depends a lot on the GC configuration and your server load, but it may take some time and if your VM has enough heap available and other things to do, the objects won't be collected "pretty soon".

The only situation where the VM specification guarantees that the GC will run, is when at some point otherwise an OutOfMemoryError would be thrown. Before throwing an OutOfMemoryError, the VM is obligated to make an attempt to at least collect so many eligible object instances, that the relevant memory allocation request can succeed (but you're still not guaranteed that all eligible instances are collected).

jarnbjo