Technically speaking, it should be impossible to create a true memory leak in a properly operating JVM that has a properly operating Garbage Collector. There is an analogous issue in Java programming where code allocates and holds onto Objects indefinitely after they are no longer needed. Is that what you are asking about?
If you are teaching people, make sure that it is clear that this is not a 'memory leak'.
People often make this mistake when using the Observer-Observable pattern i.e. Listeners and usually is when they are doing GUIs.
For example, you have a window A with a button on it. Through some mechanism, the user can open a new instance of another window B. B adds itself as a listener to the button on A. The developer has set the defaultCloseOperation of B to DISPOSE_ON_CLOSE. When the window is closed, it disapears and there is no way to get it back. However, the button on A still has a reference to the B instance as a listener. As long as A is around, no instance of B will ever be GC'd. If the user keeps opening and closing B windows, you will have an apparent 'leak' of memory.
I would say there is such a thing as a memory leak in Java. A memory leak is when you have no control over reclaiming a previously-allocated object. Such a condition occurs for example when you create a Thread object and never call start() on it. The Thread's constructor adds a reference of itself to ThreadGroup's list of Threads, and AFAIK you cannot tell the ThreadGroup to remove it.
I would say there is such a thing as a memory
leak in Java. A memory leak is when you have no
control over reclaiming a previously-allocated object.
Such a condition occurs for example when you create a
Thread object and never call start() on it. The
Thread's constructor adds a reference of itself to
ThreadGroup's list of Threads, and AFAIK you cannot
tell the ThreadGroup to remove it.
Technically, a memory leak is when an application allocates memory but then removes all references to that memory without deallocating it. In Java this condition is what causes an Object to become GC-able.
The situation you have described is analogous to a memory leak but is not one because there are still active references to that memory.
We can call this a memory leak for a lack of a better term but strictly speaking, it's not a true memory leak and I think it's important to keep that distiction clear.
warnerja, you made a good point that is very interesting to me. I support numerous application servers, but I do not write the code for the web applications which run on them. An annoying problem is java "memory leaks" which eventually fill the JVM and cause the application server to crash. The comment about the thread leak seems to be very relevent with my situation due to the threaded nature of the J2EE architecture. So I guess from here my question gets narrowed. Are there any J2EE pitfalls relating to "memory leaks"?
warnerja, you made a good point that is very
interesting to me. I support numerous application
servers, but I do not write the code for the web
applications which run on them. An annoying problem
is java "memory leaks" which eventually fill the JVM
and cause the application server to crash. The
comment about the thread leak seems to be very
relevent with my situation due to the threaded nature
of the J2EE architecture. So I guess from here my
question gets narrowed. Are there any J2EE pitfalls
relating to "memory leaks"?
Not really any different than J2SE pitfalls, such as forgetting to properly 'clean up' objects after use, such as closing streams, closing Contexts, closing JDBC Connections, etc.
There was a good Dr. Dobbs article a while back (only available for-fee now) that put objects into three categories:
(1) Allocated objects are all objects that have been created but not yet removed by the garbage collector.
(2) Reachable objects are all the allocated objects that can be reached from one of the roots.
(3) Live objects are reachable objects that are being actively used by your program.
An object is a node and references are the edges in a directed graph. The complete graph is a memory map of your application.
C++ forces you to manage both the nodes and the edges in the graph. Memory leaks in C++ are objects that fall into categories (1) and (2).
Java's GC manages the nodes for you. Java "memory leaks" are objects that fall into category (2). Objects that are reachable but not "live" can be considered memory leaks. Listeners can fall into this category.
There was a good JavaOne presentation about the topic, too, but I can't find it on-line now. Looks like getting into past JavaOne material requires a fee. - MOD
Striktly speaking there could be no memory leaks in java than those known from C/C++.
A java "memory leak" is more like holding a strong reference to an object though i would never be needed anymore. The fact that you hold a strong reference to an object prevents the GC from deallocating it.
Think of an array of objects, think of a get/put protocoll on that array (stack like). You would have something like a highwater mark on your stack.
Say you have a (sketched) get method like
public Object get() {
highWaterMark--;
return stackArray[highWaterMark];
}
what happens after 5 inserts and 3 gets...
You have a situation like this in your stackArray.
stackArray[0] = obj0
stackArray[1] = obj1
stackArray[2] = obj2 <- highWaterMark
stackArray[3] = obj3
stackArray[4] = obj4
Note that indexes 2,3 and 4 still reference objects because our get method has not cleared those array members.
Although no other party might have a strong reference to those objects the GC can't collect them because the array is still holding a strong reference.
The rule is: In any composed object free, i.e. set to null, all references to part objects as soon as possible.
"Correct" version of our stack's get method is:
public Object get() {
highWaterMark--;
final Object result = stackArray[highWaterMark];
stackArray[highWaterMark] = null; //clearing a strong reference
return result;
}
Striktly speaking there could be no memory leaks in
java than those known from C/C++.
Sure there can be. The JVM is written in a lower-level language and uses pointers internally, and if written not-quite-bug-free, could leak all on its own (and has, which is partly why there have been newer versions released). Similarly JNI components, written in C++ or what-have-you, can leak for the same reason. Granted, such JNI components aren't "pure" Java. And I'd bet the GC isn't completely bullet-proof, allowing the possibility for some objects to live on and on even though not strongly reachable anymore (because it can't really tell 100% certain that an object isn't being referenced, as currently implemented via looking at memory locations and guessing they're object references).