JDK-4185691 : Win32 huge memory leak with Tree demo using drawString()
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.2.0,1.2.2
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_2.6,windows_95,windows_nt
  • CPU: x86,sparc
  • Submitted: 1998-10-29
  • Updated: 2013-11-01
  • Resolved: 1999-10-13
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.3.0 kestrelFixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Description
Running this Tree.java test reveals a huge memory leak (~1.5mb per iteration) in the win32 JDK1.2-P build.  Verified on winNT4.0 8 & 32 bit


import java.awt.*;
import java.awt.event.*;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.*;


/**
 * Transformation of characters.
 */
public class Tree extends JPanel implements Runnable {

    private char theC = 'A';
    private Character theT = new Character(theC);
    private Character theR = new Character((char) ((int) theC + 1));
    private Thread thread;
    private BufferedImage bimg;


    public Tree() {
        setBackground(Color.white);
    }


    public void step(int w, int h) {
        theT = new Character(theC = ((char) ((int) theC + 1)));
        theR = new Character((char) ((int) theC + 1));
        if (theR.compareTo(new Character('z')) == 0) {
            theC = 'A';
        }
    }


    public void drawDemo(int w, int h, Graphics2D g2) {
        int mindim = Math.min(w, h);
        AffineTransform at = new AffineTransform();
        at.translate((w - mindim) / 2.0,
                     (h - mindim) / 2.0);
        at.scale(mindim, mindim);
        at.translate(0.5, 0.5);
        at.scale(0.3, 0.3);
        at.translate(-(Twidth + Rwidth), FontHeight / 4.0);
        g2.transform(at);
        tree(g2, mindim * 0.3, 0);

    }


    static Font theFont = new Font("Dialog", Font.PLAIN, 1);
    static double Twidth = 0.6;
    static double Rwidth = 0.6;
    static double FontHeight = 0.75;
    static Color colors[] = {Color.blue,
                             Color.red.darker(),
                             Color.green.darker()};


    public void tree(Graphics2D g2d, double size, int phase) {
        g2d.setColor(colors[phase % 3]);
        //g2d.setFont(theFont);
        g2d.drawString(theT.toString(), 0, 0);
        if (size > 10.0) {
            AffineTransform at = new AffineTransform();
            at.setToTranslation(Twidth, -0.1);
            at.scale(0.6, 0.6);
            g2d.transform(at);
            size *= 0.6;
            g2d.drawString(theR.toString(), 0, 0);
            at.setToTranslation(Rwidth+0.75, 0);
            g2d.transform(at);
            Graphics2D g2dt = (Graphics2D) g2d.create();
            at.setToRotation(-Math.PI / 2.0);
            g2dt.transform(at);
            tree(g2dt, size, phase + 1);
            g2dt.dispose();
            at.setToTranslation(.75, 0);
            at.rotate(-Math.PI / 2.0);
            at.scale(-1.0, 1.0);
            at.translate(-Twidth, 0);
            g2d.transform(at);
            tree(g2d, size, phase);
        }
    }


    public Graphics2D createGraphics2D(int w, int h) {
        Graphics2D g2 = null;
        if (bimg == null || bimg.getWidth() != w || bimg.getHeight() != h) {
            bimg = (BufferedImage) createImage(w, h);
        } 
        g2 = bimg.createGraphics();
        g2.setBackground(getBackground());
        g2.clearRect(0, 0, w, h);
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
        return g2;
    }


    public void paint(Graphics g) {
	Dimension d = getSize();
        step(d.width, d.height);
        Graphics2D g2 = createGraphics2D(d.width, d.height);
        drawDemo(d.width, d.height, g2);
        g2.dispose();
        g.drawImage(bimg, 0, 0, this);
    }


    public void start() {
        thread = new Thread(this);
        thread.setPriority(Thread.MIN_PRIORITY);
        thread.start();
    }


    public synchronized void stop() {
        thread = null;
    }


    public void run() {
        try {
            thread.sleep(2222);
        } catch (InterruptedException e) { return; }
        Thread me = Thread.currentThread();
        while (thread == me) {
            repaint();
            try {
                thread.sleep(1111);
            } catch (InterruptedException e) { break; }
        }
        thread = null;
    }


    public static void main(String argv[]) {
        final Tree demo = new Tree();
        JFrame f = new JFrame("Java2D Demo - Tree");
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {System.exit(0);}
            public void windowDeiconified(WindowEvent e) { demo.start(); }
            public void windowIconified(WindowEvent e) { demo.stop(); }
        });
        f.getContentPane().add("Center", demo);
        f.pack();
        f.setSize(new Dimension(400,300));
        f.show();
        demo.start();
    }
}

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: kestrel FIXED IN: kestrel INTEGRATED IN: kestrel VERIFIED IN: merlin
14-06-2004

PUBLIC COMMENTS The native glyph cache is allowing too many glyphs into the cache.
10-06-2004

EVALUATION In order to reproduce the problem I've made Java application within the example placed into this bug report. I performed the run of application over night within fcs-P build. Memory consumtion was reasonable. On the start memory went from 35592K to 45780K and with little drift stabilized at 45772K +- 20K. For fcs-O the same result was observed: 35592K -> 45768K(max) ->45768K +- 20K. dmitry.feld@eng 1998-11-04 After commenting out g2d.setFont(theFont) call we get default font of 12 points size. After affine transform applied to theis font we've got result glyph size 170 points. It leads to allocation of cache item of 170 * 170 * 4 (for 32bits graphics) which is 88K per glyph. We show more than 100 glyphs (9M) of bitmaps plus generating intermediate Graphics2D instance for every glyph (for transform) and so on. In machine with 64M of VM we ran out of memory. After all we ended up with 113M of memory allocated. It suggests we shall review our cache design. dmitry.feld@eng 1998-11-04
04-11-1998