Re: Resource Leak

Hi Doug-

Whoa!  That's some leak.

Doug Lindholm wrote:


A few months back I reported a problem I was seeing with running out of
memory. It has now escalated to become a show-stopping problem. I've
been doing some profiling to see where the resources are going.

I've attached a simple sample program that demonstrates one such case. I
make a Display, add a ScalarMap to it, then repeatedly setRange. When
using a DisplayImplJ3D the instance count of Object[] and many java3d
classes continues to grow. There is no such problem with the
DisplayImplJ2D. I know very little about java3d. I'm hoping there is
something VisAD can do to free up java3d resources and that this is not
a java3d bug that we have no control over.

Any ideas?


I modified your test slightly to add the display to a frame.
When I did this, my total memory useage stayed around 7 Mb
and I could see garbage collection running.

If I don't add the display to a frame, memory use shoots
through the roof.  I've attached the revised program and
a small memory monitor program.  If you pass in a parameter
to the MemoryTest, it will show the display, otherwise,
just the monitor.

I don't have time to track down the cause, but maybe this
will help Tom Rink or one of the other developers.  Thanks
for the test program.

Don
*************************************************************
Don Murray                               UCAR Unidata Program
dmurray@xxxxxxxxxxxxxxxx                        P.O. Box 3000
(303) 497-8628                              Boulder, CO 80307
http://www.unidata.ucar.edu/staff/donm
*************************************************************

import visad.*;
import visad.java2d.*;
import visad.java3d.*;
import javax.swing.*;
import java.awt.event.*;

public class MemoryTest {

    public void init(boolean showDisplay) {
        try {
            //System.out.println("make display");
            //DisplayImplJ2D display = new DisplayImplJ2D( "test" );
            DisplayImplJ3D display = new DisplayImplJ3D( "test" );
            //DisplayImplJ3D display = new DisplayImplJ3D( "test", new 
TwoDDisplayRendererJ3D() );
            //System.out.println("make map");
            ScalarMap xmap = new ScalarMap( RealType.Time, Display.XAxis );
            //System.out.println("add map");
            display.addMap(xmap);
            JFrame frame = new JFrame("Memory Test");
            frame.addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
            if (showDisplay) frame.getContentPane().add(display.getComponent());
            frame.getContentPane().add("South", new MemoryMonitor());
            frame.pack();
            frame.show();


            int count = 0;
            while ( true ) {
                double now = (double) (System.currentTimeMillis() / 1000.0);
                //  System.out.println("step " + count++ + " now = " + now );
                double then = now - 3600.0;
                xmap.setRange(then, now);
                //Thread.sleep(10);
            }       
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }

    public static void main(String[] args) {
        MemoryTest test = new MemoryTest();
        test.init(args.length > 0);
    }
}
// $Id: MemoryMonitor.java,v 1.4 2002/05/03 13:54:42 dmurray Exp $
/*
 * Copyright 1997-2000 Unidata Program Center/University Corporation for
 * Atmospheric Research, P.O. Box 3000, Boulder, CO 80307,
 * support@xxxxxxxxxxxxxxxxx
 * 
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at
 * your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 */


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


public class MemoryMonitor  extends JPanel implements Runnable
{
    boolean running = false;
    long sleepInterval  = 2000;
    Thread thread;
    int percentThreshold = 80;
    int timesAboveThreshold = 0;
    static DecimalFormat fmt =  new DecimalFormat("#0.00 MB");
    JLabel label1 = new JLabel ("");
    JLabel label2 = new JLabel ("");
    Color labelForeground;

    public MemoryMonitor () {
        
        setLayout (new FlowLayout (FlowLayout.LEFT));
        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
        add(label1);
        add(label2);
        //GuiUtils.hbox (this, Misc.newList (label1, label2));
        MouseListener ml = new MouseAdapter () {
                public void mouseClicked (MouseEvent e) {
                    if (running) stop ();
                    else start ();
                }
            };
        labelForeground = label2.getForeground ();
        label1.addMouseListener (ml);
        label2.addMouseListener (ml);
        start ();
    }

    private synchronized void  stop () {
        running = false;
        label1.setEnabled (false);
        label2.setEnabled (false);
    }



    private synchronized void  start () {
        if (running) return;
        label1.setEnabled (true);
        label2.setEnabled (true);
        running = true;
        thread = new Thread ( this, "Memory monitor");
        thread.start ();
    }


    private void showStats () {
        double totalMemory = (double) Runtime.getRuntime ().totalMemory ();
        double freeMemory = (double) Runtime.getRuntime ().freeMemory ();
        double usedMemory = (totalMemory-freeMemory);
        int percent = (int)(100.0*(usedMemory/totalMemory));
        totalMemory = totalMemory/1000000.0;
        usedMemory = usedMemory/1000000.0;
        label1.setText ("Memory usage:   total: " + fmt.format (totalMemory) + 
                        "   used: " + fmt.format (usedMemory));
        label2.setText ("  (" + percent +"%)");

        // doing this continually slows things down
        //Runtime.getRuntime ().gc (); 
        if (percent > percentThreshold) {
            timesAboveThreshold ++;
            if (timesAboveThreshold > 5)
                label2.setForeground (Color.red);
            Runtime.getRuntime ().gc ();

        } else {
            label2.setForeground (labelForeground);
            timesAboveThreshold = 0;
        }
    }

    public void run () {
        while (running) {
            showStats ();
            try {thread.sleep (sleepInterval);} catch (Exception exc) {}
        }
    }

    public void setRunning  (boolean r) {
        running = r;
    }

    public boolean getRunning  () {
        return running;
    }

    public static void main (String[]args) {
        JFrame f = new JFrame ();
        MemoryMonitor mm = new MemoryMonitor ();
        f.getContentPane ().add (mm);
        f.pack ();
        f.show ();
    }


}