Hello,

I am still fighting with "dispose()" problems, and I discovered something, which I consider a bug (it appears in 1.5.1 release and in a latest version from CVS head).
The problem is when I call method "suspendProcessing()" followed by "dispose()" on JSVGCanvas object,
the JSVGCanvas won't be collected by garbage collector. This is somehow connected with UpdateManager ant its RunnableQueue, I think.
You may ask why i call dispose() after suspendProcessing() (why not only dispose()). The answer is that  I have my own queue of events in my application, and sometimes I get a request to deactivate the SVG screen (suspendProcessing), and soon after that to close it (close). I handle these events one after another (of course AWT in event dispatch thread).

The sample code is:
MemoryLeakTest.java:
-----------------------------------
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.net.URLConnection;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.util.XMLResourceDescriptor;
import org.w3c.dom.Document;
import org.w3c.dom.svg.SVGDocument;

public class MemoryLeakTest extends JFrame {
  JPanel left;
  JPanel right = new JPanel();
  Document doc = null;
  JSVGCanvas canvas = null;

  public MemoryLeakTest() {
    right.setLayout(new BorderLayout());
    this.getContentPane().setLayout(new BorderLayout());
    this.setSize(new Dimension(1024, 768));
    this.setTitle("MemoryTestLeak");
    JButton button1 = new JButton("Start");
    JButton button2 = new JButton("Stop");
    JButton button3 = new JButton("GC");
    button1.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        start();
      }
    });
    button2.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        stop();
      }
    });
    button3.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        gc();
      }
    });
    left = new JPanel();
    left.setLayout(new BoxLayout(left, BoxLayout.Y_AXIS));
    left.add(button1);
    left.add(button2);
    left.add(button3);
    this.getContentPane().setLayout(new BorderLayout());
    this.getContentPane().add(left, BorderLayout.WEST);
    this.getContentPane().add(right, BorderLayout.CENTER);
    start();
  }

  private void start() {
    if (canvas == null) {
      canvas = new JSVGCanvas();
      final ReferenceQueue rq = new ReferenceQueue();
      final WeakReference ref = new WeakReference(canvas, rq);
      new Thread() {
        public void run() {
          try {
            rq.remove();
            System.out.println("CANVAS removed "+ref);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
      .start();
      try {
        loadDocument();
      } catch (Exception e) {
        e.printStackTrace();
      }
      right.add(canvas, BorderLayout.CENTER);
      pack();
    }
  }

  private void stop() {
    if (canvas!=null) {
      canvas.suspendProcessing();
      canvas.dispose();
      canvas = null;
      doc = null;
      right.removeAll();
      this.invalidate();
      this.pack();
      System.out.println(
        Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
    }
  }

  private void gc() {
    System.gc();
    System.out.println(
      Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
  }

  private void loadDocument() throws Exception {
    String stringURL = "file:circle.svg";
    Reader reader = null;
    SVGDocument svgDoc = null;
    URL url = "" URL(stringURL);
    URLConnection connection;
    connection = url.openConnection();
    reader = new InputStreamReader(connection.getInputStream());
    String parser = XMLResourceDescriptor.getXMLParserClassName();
    SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
    doc = f.createSVGDocument("file:circle.svg", reader);
    canvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC);
    canvas.setDoubleBufferedRendering(true);
    canvas.setSize(new Dimension(800, 600));
    canvas.setDocument(doc);
  }

  public static void main(String[] args) {
    JFrame frame = new MemoryLeakTest();
    frame.pack();
    frame.setVisible(true);
  }
}
-------------------------------
 
circle.svg:
---------------------------
<?xml version="1.0" encoding="windows-1250" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "
http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="12cm" height="4cm" viewBox="0 0 1200 400"
     xmlns="
http://www.w3.org/2000/svg" version="1.1">
  <desc>Example circle01 - circle filled with red and stroked with blue</desc>
  <circle cx="600" cy="200" r="100"
        fill="red" stroke="blue" stroke-width="10"  />
 
</svg>
------------------------------
 
After pressing stop and then gc one should see "CANVAS removed [EMAIL PROTECTED]" message, but it appears hardly ever.
 
Regards,
Lukasz

Reply via email to