Garbage Collection behavior

Y

Yin99

Can anyone technically explain what is happening between these two
classes, ClassA and ClassB. If you Set the variable
"CLEANUP_ACTIONLISTENERS" in ClassA to true, it garbage collects ClassB
(i.e. you can click on the Button in ClassA unlimited times without
memory problems.) Set this variable to false, and ClassB is no longer
garbage collected, and you get "java.lang.OutOfMemoryError" after
clicking the button in ClassA many times (about 8-9 clicks on my
machine.)

Why is ClassB only being garbage collected when it's ActionListener is
removed? Thanks,

Yin99

ClassA
------
package testing;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ClassA
extends JFrame {


/** TRUE ALLOWS GARBAGE COLLECTION, FALSE CAUSES MEMORY LEAK */
private static final boolean CLEANUP_ACTIONLISTENERS = false;
/************************************************************/



//ClassB Contains a Panel that uses ActionListener
ClassB testB = null;

//Keep track of ClassA Button Clicked and Instantiations of ClassB
private int counter = 0;

//ClassA GUI Elements
JButton jButtonA = new JButton();
JPanel jPanelClassA = new JPanel();
BorderLayout borderLayoutClassA = new BorderLayout();

//ClassA Constructor
public ClassA() {
jbInitClassA();
}

//ClassA GUI Building Method
private void jbInitClassA(){
if(this.getContentPane().getComponentCount() == 0){
jButtonA.setText("Clicked: " +counter);
jButtonA.addActionListener(new
ClassA_jButtonA_actionAdapter(this));
jPanelClassA.setMaximumSize(new Dimension(32767, 32767));
jPanelClassA.setLayout(borderLayoutClassA);
this.getContentPane().add(jPanelClassA, BorderLayout.CENTER);
jPanelClassA.add(jButtonA, BorderLayout.SOUTH);
}
}


//ClassA's ActionListener Action Performed for JButtonA
void jButtonA_actionPerformed(ActionEvent e) {


if ( (testB != null) & (CLEANUP_ACTIONLISTENERS)) {
//kill method calls removeActionListener in ClassB
testB.ClassBremoveActionListener();
}

//new ClassB should remove reference testB had to old ClassB
//causing old ClassB to be available for Garbage Collection
testB = new ClassB();
counter++;

//Display Counter
jButtonA.setText("ClassA Clicked: " +Integer.toString(counter));

jPanelClassA.add(jButtonA, BorderLayout.SOUTH);
//Add Panel from ClassB into ClassA Panel
jPanelClassA.add(testB.jPanelClassB, BorderLayout.CENTER);
jPanelClassA.revalidate();
jPanelClassA.repaint();

}

public static void main(String[] args) {
ClassA classA1 = new ClassA();
classA1.setSize(200, 200);
classA1.show();
}

}


class ClassA_jButtonA_actionAdapter
implements java.awt.event.ActionListener {
ClassA adaptee;

ClassA_jButtonA_actionAdapter(ClassA adaptee) {
this.adaptee = adaptee;
}

public void actionPerformed(ActionEvent e) {
adaptee.jButtonA_actionPerformed(e);
}
}

ClassB
------
package testing;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class ClassB extends JFrame {

/** Memory Allocating Variable */
private Object[][] eatMemory = new Object[10000][200];

/** ClassB GUI Objects */
public JPanel jPanelClassB = new JPanel();
private JButton jButtonClassB = new JButton();
private BorderLayout borderLayoutClassB = new BorderLayout();

/** ClassB ActionListener for jButtonClassB */
private ClassB_jButtonClassB_actionAdapter myActionB = null;

//ClassB Constructor
public ClassB() {
jbInitClassB();
}

//ClassB GUI Building Method
private void jbInitClassB() {
if (myActionB == null) {
myActionB = new ClassB_jButtonClassB_actionAdapter(this);
jButtonClassB.addActionListener(myActionB);
}
jPanelClassB.setLayout(borderLayoutClassB);
jButtonClassB.setText("ClassB");
jPanelClassB.add(jButtonClassB, BorderLayout.CENTER);
this.getContentPane().add(jPanelClassB, BorderLayout.CENTER);
}

void jButtonClassB_actionPerformed(ActionEvent e) {
jButtonClassB.setText("ClassB");
}

//Method to remove ActionListener from ClassB's jButtonClassB
public void ClassBremoveActionListener() {
jButtonClassB.removeActionListener(myActionB);
}
}

class ClassB_jButtonClassB_actionAdapter implements
java.awt.event.ActionListener {
ClassB adaptee;

ClassB_jButtonClassB_actionAdapter(ClassB adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jButtonClassB_actionPerformed(e);
}
}
 
B

Bob

Yin99 said:
Why is ClassB only being garbage collected when it's ActionListener is
removed? Thanks,

Is it because of this?

myActionB = new ClassB_jButtonClassB_actionAdapter(this);
jButtonClassB.addActionListener(myActionB);


myActionB contains a reference to the this instance of ClassB. Then you
offer myActionB to an instance jButtonClassB.

So jButtonClassB will continue to have a reference to an instance of
ClassB, which means ClassB will not be eligible for garbage collection.

Only when there are NO live threads that have access to an object, will
that object become eligible for garbage collection. And, even then,
garbage collection is not guaranteed to happen when you request it. (The
JVM decides what to do and when.)

But perhaps I have missed something, because I've not used GUI code for
some time, and I don't know about jButtonClassB and what refers to it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,979
Messages
2,570,185
Members
46,727
Latest member
FelicaTole

Latest Threads

Top