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);
}
}
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);
}
}