Apparent Memory Leak in Microsoft Java

This applet demonstrates an apparent memory leak in Microsoft's implementation of Java (1.1.4).  The leak does not occur in Sun Java 1.5.0_05.

To demonstrate the problem, run the applet in a copy of Microsoft Internet Explorer that is using the Microsoft Virtual Machine (the applet reports the Java version in the purple rectangle).  Open the Java Console and monitor the read-out of memory use.  Click repeatedly on Buttons in the Frame that pops up.  The memory use will increase with no apparent limit (it was tested up to 80 MB). 

Using the Sun JVM the memory stays under 5 MB. 

Although the Microsoft VM has been discontinued, it would be helpful to know how to avoid memory leaks since many browsers still use the Microsoft VM.

If the ButtonPanel is placed directly in the applet instead of a Frame there is no leak in either Microsoft or Sun JVM, but many programs need to use Frames.  The absence of an increase in memory use by the non-Frame version suggests there is really a memory leak here, rather than the Microsoft VM just avoiding garbage collection until it uses a huge amount of memory.

If you have any insights, workarounds or comments about this test page please contact Mickey Segal.  A listing of  many Java resources is at this link.

Source code:

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class leak2 extends Applet {

public void init()
{
    setBackground(new Color(225,225, 255));
    try
    {
        FrameForApplet frameForApplet = new FrameForApplet("A frame");
    }
    catch (Throwable e)
    {
        System.out.println("Can't use Frame: " + e);
        return;
    }
}

public void paint(Graphics g)
{
    g.drawString("A Frame appears using Java version " + System.getProperty("java.version"), 10 , 25);
}
} // END OF Class leak2


final class FrameForApplet extends Frame {

ButtonPanel buttonPanel;
int panelNow;
static final int RED = 0;
static final int GREEN = 1;

FrameForApplet(String s)
{
    super(s);
    setLayout(new GridBagLayout());
    addNotify();
    setBounds(400, 100, 400, 400);
    changeToPage(GREEN);
    show();
}

final void changeToPage(int newPanel)
{
    if (buttonPanel != null)
    {
        buttonPanel = null;
        removeAll();
    }
    Runtime.getRuntime().gc();
    System.out.println("total = " + Runtime.getRuntime().totalMemory() + "\t free + " + Runtime.getRuntime().freeMemory());
    if (newPanel == GREEN)
    {
        buttonPanel = new ButtonPanel(GREEN, this);
        add(buttonPanel);
    }
    else if (newPanel == RED)
    {
        buttonPanel = new ButtonPanel(RED, this);
        add(buttonPanel);
    }
    panelNow = newPanel;
    validate();
}
} // END OF Class FrameForApplet


class ButtonPanel extends Panel implements ActionListener {

static int buttons = 100;
int now;
Button[] button;
FrameForApplet container;

ButtonPanel(int now, FrameForApplet container)
{
    this.container = container;
    this.now = now;
    Color buttonColor = (now == 1)? Color.green : Color.red;
    setLayout(new GridLayout(buttons/10, 10, 4, 4));
    button = new Button[buttons];
    for (int i=0; i<buttons; i++)
    {
        button[i] = new Button();
        button[i].setBackground(buttonColor);
        button[i].addActionListener(this);
        add(button[i]);
    }
}

public void actionPerformed(ActionEvent ae)
{
    container.changeToPage(1-now);
}
} // END OF Class ButtonPanel