Programming Tutorials Browser Tutorials Articles Struts Tutorials Hibernate Tutorials

  Tutorial: Java Tip 79: Interact with garbage collector to avoid memory leaks - JavaWorld

Java Tip 79: Interact with garbage collector to avoid memory leaks - JavaWorld

Tutorial Details:

Java Tip 79: Interact with garbage collector to avoid memory leaks
Java Tip 79: Interact with garbage collector to avoid memory leaks
By: By Raimond Reichert
Use reference objects to prevent memory leaks in applications built on the MVC pattern
bject-oriented programs and class libraries often use the model-view-controller (MVC) design pattern. Swing, for example, uses it extensively. Unfortunately, using MVC in a garbage-collected environment such as Java introduces additional serious problems. Imagine, for instance, that your program uses a data model that exists for the lifetime of your application. A user can create views of that model. When he loses interest in the view, he can dispose of it -- or he'll want to dispose of it, at any rate. Unfortunately, the view is still registered as a listener of the data model and cannot be garbage-collected. Unless you explicitly remove every view from the data model's listeners list, you will get loitering zombie objects. The garbage collector can still reach these objects, even though you will never use them and want the garbage collector to discard them.
This Java tip shows you how to use reference objects, introduced in JDK 1.2, to solve this problem. By interacting with the garbage collector, you can eliminate loiterers and lapsed listeners, terms suggested by Ed Lycklama (see the Resources section below for more details). Lycklama generally defines a loiterer as an object that persists past its usefulness. The loiterer category is further broken down into four patterns; most common is the lapsed listener, an object added to, but never removed from, a collection of listeners.
Example problem
In this article, I'll examine a simple Swing MVC application to illustrate how an application using the MVC pattern creates lapsed listeners and memory leaks. Then, I'll show you how to modify the application in order to remove the memory leaks. The example application has a simple data model that contains some strings. The application's main window, shown in Figure 1, lets the user add new strings to, and create new views of, the data model. Both processes are illustrated in the figure below. The application's main window also shows the number of views that are alive , meaning that they are created, but not yet finalized. Each view is a separate frame containing a Jlist, which displays the strings from the data model (not shown here). A view listens to changes in the data model and updates itself accordingly. You will find the full source for this example in Resources .
Figure 1. The application's main window
First, I am going to define the example data model, but not implement it. Then, I'll implement that model's view. Finally, I'll actually implement the data model in four different ways, showing different implementation trade-offs.
Defining the model
The interface VectorModel defines the data model of the example application:
VectorModel.java
package mldemo;
import java.util.*;
/**
* Define a simple "application" data model. You can add, remove, and
* access objects. When you add or remove an object, all
* registered VectorModel.Listener s
* will be notified with a VectorModel.Event .
*
* @author Raimond Reichert
*/
public interface VectorModel {
public static class Event extends EventObject {
private Object element;
public Event (VectorModel model, Object element) {
super (model);
this.element = element;
}
public Object getElement() {
return element;
}
}
public interface Listener extends EventListener {
public void elementAdded (VectorModel.Event e);
public void elementRemoved (VectorModel.Event e);
}
public void addElement (Object object);
public void removeElement (Object object);
public Object elementAt (int index);
public int size();
public void addListener (VectorModel.Listener l);
public void removeListener (VectorModel.Listener l);
}
Whenever an element is added to or removed from the vector, the
VectorModel 's implementations must notify their listeners.
Implementing the view
VectorListFrame , the view of this model, is a JFrame subclass that contains a JList. When a new VectorListFrame object is created, the contents of the VectorModel are copied into the list's DefaultListModel . VectorListFrame has an anonymous inner class that implements the VectorModel.Listener interface. This inner class is registered as a listener to the VectorModel .
Upon the arrival of a vector event, the inner class delegates the appropriate change to the DefaultListModel instance. For tracking purposes, the constructor of VectorListFrame increases the count of living views stored in the public static field nFrames , while the finalize method decreases that counter. The application's main window uses nFrames to display the number of living views.
VectorListFrame.java
package mldemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* Displays a VectorModel in a small frame, using a
* JList . Uses a private, anonymous inner class to
* implement VectorModel.Listener . This inner class
* adds or removes elements from the JList 's data
* model.
*
Note: As the code's out-commented lines show, in the case
* of VectorListFrame , it would be quite easy to
* remove the object from the VectorModel 's listeners list
* when the frame is closed. Alas, in real-world code, it's not always
* this easy...
*
* @author Raimond Reichert
*/
public class VectorListFrame extends JFrame {
// number of non-finalized VectorListFrames
public static int nFrames = 0;
// Commenting out discussed below...
// private VectorModel vectorModel;
protected DefaultListModel listModel;
protected VectorModel.Listener
modelListener = new VectorModel.Listener() {
public void elementAdded (VectorModel.Event e) {
listModel.addElement (e.getElement());
}
public void elementRemoved (VectorModel.Event e) {
listModel.removeElement (e.getElement());
}
};
public VectorListFrame (VectorModel vectorModel) {
super ("Listing...");
setSize (200, 200);
setDefaultCloseOperation (WindowConstants.DISPOSE_ON_CLOSE);
// In a multi-threaded environment (like Java) you
// must synchronize the increment and decrement
// operations on "nFrames." You can't synchronize
// on the object being constructed, but must have all
// constructors synchronize on the same object. The
// java.lang.Class object for VectorListFrame is
// a good candidate for this synchronization.
synchronized (VectorListFrame.class) {
nFrames++;
}
listModel = new DefaultListModel();
int size = vectorModel.size();
for (int i = 0; i < size; i++)
listModel.addElement (vectorModel.elementAt(i));
getContentPane().add (new JScrollPane (new JList (listModel)));
vectorModel.addListener (modelListener);
// Commenting out discussed below...
// this.vectorModel = vectorModel;
}
/* Commenting out discussed below...
public void dispose() {
super.dispose();
vectorModel.removeListener (modelListener);
}
*/
protected void finalize() throws Throwable {
super.finalize();
synchronized (VectorListFrame.class) {
nFrames--;
}
}
}
When you close the frame, its dispose method is called. In this example, you could easily remove the VectorListFrame from the data model's listeners list. All you need to do is keep a reference to the VectorModel . Then you could call the model's removeListener method from within the view's dispose method (see the code that has been commented out for the implementation).
However, things might not be this simple in a real-world application. The view that is listening to the data model might be deeply nested in a containment hierarchy. To remove it from the model's listeners list, the top-level frame would need to keep a reference to both the model and its view. This is a very error-prone business tactic, and makes for ugly, difficult-to-maintain code. If you forget just one model/view pair, you create a lapsed listener and memory will be leaked. You therefore want a data model that removes lapsed listeners automatically.
I will cover four implementations of VectorModel . The first one is the standard model for implementation; this is how view models in Swing are implemented. The other three implementations use weak references to avoid the lapsed listener problem. You can start the demo application four ways to see these implementations:
java mldemo.MLDemo , java mldemo.MLDemo wr , java mldemo.MLDemo twr , and java mldemo.MLDemo qwr .
The standard model implementation
The standard way of implementing a model, such as VectorModel , is straightforward. One vector stores the data elements, and another holds the references to the VectorModel.Listener 's objects. This is how the class DefaultVectorModel implements VectorModel .
The implementation has a field, called listeners , that is the vector holding the listeners. Adding a listener to the vector, and notifying all listeners, is very easy and straightforward:
// in DefaultVectorModel.java (see Resources )
private Vector listeners;
// ...
public void addListener (VectorModel.Listener l) {
listeners.addElement (l);
}
// ...
protected void fireElementAdded (Object object) {
VectorModel.Event e = null;
int size = listeners.size();
for (int i = 0; i < size; i++) {
if (e == null) // lazily create event
e = new VectorModel.Event (this, object);
((VectorModel.Listener)listeners.elementAt(i)).elementAdded (e);
}
}
The drawback of this approach, of course, is that you can easily get lapsed listeners. The model doesn't know when a listener is just loitering -- that is to say, when it's only reachable through its own vector. When a model is the only object that still knows about a listener object, you should be able to release the listener. In other words, you need the data model to be sensitive to its listener's reachability.
Interacting with the garbage collector
The java.lang.ref package lets you interact with the garbage collector. The basic idea is not to reference objects


 

Read Tutorial at: Click here to view the tutorial

Rate Tutorial:
Java Tip 79: Interact with garbage collector to avoid memory leaks - JavaWorld

View Tutorial:
Java Tip 79: Interact with garbage collector to avoid memory leaks - JavaWorld

Related Tutorials:

Reloading Applets
Reloading Applets
 
Applet to Applet Communication
Applet to Applet Communication
 
Java memory management
Java memory management
 
Clearing resources
Clearing resources
 
Master Merlin's new I/O classes
Master Merlin's new I/O classes
 
Diagnose common runtime problems with hprof
Diagnose common runtime problems with hprof
 
Java security evolution and concepts, Part 2
Java security evolution and concepts, Part 2
 
Pick up performance with generational garbage collection
Pick up performance with generational garbage collection
 
Put Java in the fast lane
Put Java in the fast lane
 
J2ME devices: Real-world performance
J2ME devices: Real-world performance
 
Java Tip 132: The taming of the thread
Java Tip 132: The taming of the thread
 
Attack of the clones
Attack of the clones
 
J2SE 1.4.1 boosts garbage collection
J2SE 1.4.1 boosts garbage collection
 
Into the mist of serializaton myths
Into the mist of serializaton myths
 
Profiling the profilers
Profiling the profilers
 
Tuning garbage collection in the HotSpot JVM
Packing 100 megabytes of garbage into a 50 megabyte bag.
 
Garbage Collection in the Java HotSpot Virtual Machine
Garbage Collection in the Java HotSpot Virtual Machine Gain a better understanding of how garbage collection in the Java HotSpot VM works, and learn to take full advantage of it when designing, developing, and deploying your Java applications.
 
Asking "Why" at Sun Laboratories: A Conversation with Director, Glenn Edens
Sun Laboratories Director, Glenn Edens, discusses new research developments in the Java language and the gratifications and trials of running a research lab.
 
Core Java Interview Questions!
Core Java Interview Questions! Core Java Interview Questions Question: What is transient variable? Answer: Transient variable can't be serialize. For example if a variable is declared as transient in a Serializable class and the class is written
 
New Technical Articles: 64-bit Programming on Solaris 10 OS for x86 Platforms
Four technical articles describe the new Sun Studio 10 software's 64-bit programming features on the Solaris 10 OS for x86 and AMD64 platforms. Important issues regarding the AMD64 ABI (Application Binary Interface), debugging, migration to 64-bits, and p
 
Site navigation
 

 

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright © 2006. All rights reserved.