You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-users@xmlgraphics.apache.org by "Spasojevic, Daniel" <Sp...@AUSTRALIA.Stortek.com> on 2003/06/16 02:01:20 UTC
Object retention when using removeChild
Hi,
Firstly, I think that the Batik SVG toolkit is very good, and I have been
very impressed with the overall quality and number of features implemented.
I am having trouble removing nodes from a SVG document that has been
associated with a JSVGCanvas object. The problem is that although calling
removeChild() stops the nodes from being displayed, it seems that the
objects associated with that node are retained - preventing the removed
nodes from being garbage collected. I am using Batik 1.5, the problem
appears when using 1.4.1_02 and 1.4.1_03 of Java, and under Windows 2000 and
KDE on linux.
Hopefully this is due to a coding error on my part.
There is a similiar message in the user archives at
http://koala.ilog.fr/batik/mlists/batik-users/archives/msg02214.html.
Although the message was replied to, I couldn't see anything to help solve
my problem.
I wrote a simple test program that built a SVG document that included a text
element, associated it with a JSVGCanvas, then removed all child nodes of
the document root. Using JProfiler, I found the following references to
associated SVGOMTextElement (the format of this output is: name of the
referant, number of references, total size of references):
--- Incoming references before removeChild()
class array content 6 784
field e of org.apache.batik.bridge.SVGTextElementBridge 1 40
field key of java.util.HashMap$Entry 1 24
field lastChild of org.apache.batik.dom.AbstractParentNode$ChildNodes 1
24
field nextSibling of org.apache.dom.svg.SVGOMRectElement 1
56
field ownerElement of org.apache.batik.dom.GenericAttr 2
80
field parentNode of org.apache.batik.dom.GenericText 1
40
field target of org.apache.batik.bridge.BridgeContext$EventListenerMememto
2 48
field target of org.apache.batik.dom.event.DOMMutationEvent
2 112
field this$0 of org.apache.batik.dom.AbstractParentNode$ChildNodes
1 24
field this$0 of
org.apache.batik.dom.AbstractParentNode$ExtendedNamedNodeHashMap 1
24
field this$0 of
org.apache.batik.dom.AbstractParentNode$ExtendedNamedNodeHashMap 1
24
field value of java.util.HashTable$Entry
1 24
field value of java.util.HashTable$Entry
1 24
--- Incoming references after removeChild()
class array content 6 784
field e of org.apache.batik.bridge.SVGTextElementBridge 1 40
field ownerElement of org.apache.batik.dom.GenericAttr 2 80
field parentNode of org.apache.batik.dom.GenericText 1 40
field target of org.apache.batik.bridge.BridgeContext$EventListenerMememto
2 48
field this$0 of org.apache.batik.dom.AbstractParentNode$ChildNodes
1 24
field this$0 of
org.apache.batik.dom.AbstractParentNode$ExtendedNamedNodeHashMap 1
24
field this$0 of
org.apache.batik.dom.AbstractParentNode$ExtendedNamedNodeHashMap 1
24
field value of java.util.HashTable$Entry
1 24
These references are preventing the object from being garbage collected.
After many additions and removals during the execution of my application,
this causes a significant increase in the memory used.
I have included the source code to the test program below. It is really just
an amateurish mish-mash of the DOM API and JSVGCanvas tutorials.
Any help as to how to prevent this object retention would be very much
appreciated.
-Daniel Spasojevic
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.w3c.dom.DOMImplementation;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.swing.svg.JSVGComponent;
import org.apache.batik.swing.gvt.GVTTreeRendererAdapter;
import org.apache.batik.swing.gvt.GVTTreeRendererEvent;
import org.apache.batik.swing.svg.SVGDocumentLoaderAdapter;
import org.apache.batik.swing.svg.SVGDocumentLoaderEvent;
import org.apache.batik.swing.svg.GVTTreeBuilderAdapter;
import org.apache.batik.swing.svg.GVTTreeBuilderEvent;
import org.apache.batik.swing.svg.SVGLoadEventDispatcherAdapter;
import org.apache.batik.swing.svg.SVGLoadEventDispatcherEvent;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Document;
import org.w3c.dom.svg.SVGDocument;
public class SVGApplication {
public static void main(String[] args) {
JFrame f = new JFrame("Batik");
SVGApplication app = new SVGApplication(f);
f.getContentPane().add(app.createComponents());
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setSize(400, 400);
f.setVisible(true);
app.buildDoc();
}
JFrame frame;
JButton button = new JButton("Load...");
JLabel label = new JLabel();
JSVGCanvas svgCanvas = new JSVGCanvas();
Document svgDocument;
Element topLevelElt;
DOMImplementation sImpl;
String svgNS;
Thread processUserThread;
public SVGApplication(JFrame f) {
frame = f;
}
public JComponent createComponents() {
final JPanel panel = new JPanel(new BorderLayout());
JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));
p.add(button);
p.add(label);
panel.add("North", p);
panel.add("Center", svgCanvas);
// Set the button action.
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
JFileChooser fc = new JFileChooser(".");
int choice = fc.showOpenDialog(panel);
if (choice == JFileChooser.APPROVE_OPTION) {
File f = fc.getSelectedFile();
try {
svgCanvas.setURI(f.toURL().toString());
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
});
svgCanvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC);
// Set the JSVGCanvas listeners.
svgCanvas.addSVGDocumentLoaderListener(new
SVGDocumentLoaderAdapter() {
public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
label.setText("Document Loading...");
}
public void documentLoadingCompleted(SVGDocumentLoaderEvent e) {
label.setText("Document Loaded.");
}
});
svgCanvas.addGVTTreeBuilderListener(new GVTTreeBuilderAdapter() {
public void gvtBuildStarted(GVTTreeBuilderEvent e) {
label.setText("Build Started...");
}
public void gvtBuildCompleted(GVTTreeBuilderEvent e) {
label.setText("Build Done.");
frame.pack();
}
});
svgCanvas.addGVTTreeRendererListener(new GVTTreeRendererAdapter() {
public void gvtRenderingPrepare(GVTTreeRendererEvent e) {
label.setText("Rendering Started...");
}
public void gvtRenderingCompleted(GVTTreeRendererEvent e) {
label.setText("Render complete");
processUserThread = new Thread(new Runnable(){
public void run(){
System.err.println("Second thread");
doUserLoop();
}
});
processUserThread.start();
}
});
svgCanvas.addSVGLoadEventDispatcherListener(new
SVGLoadEventDispatcherAdapter(){
public void
svgLoadEventDispatchStarted(SVGLoadEventDispatcherEvent e){
label.setText("load event dispatch started");
}
});
sImpl = SVGDOMImplementation.getDOMImplementation();
svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
return panel;
}
public void buildDoc(){
svgDocument = (SVGDocument)sImpl.createDocument(svgNS, "svg", null);
topLevelElt = svgDocument.getDocumentElement();
topLevelElt.setAttributeNS(null, "width", "600");
topLevelElt.setAttributeNS(null, "height", "450");
// create the rectangle
Element rectangle = svgDocument.createElementNS(svgNS, "rect");
rectangle.setAttributeNS(null, "x", "10");
rectangle.setAttributeNS(null, "y", "20");
rectangle.setAttributeNS(null, "width", "100");
rectangle.setAttributeNS(null, "height", "50");
rectangle.setAttributeNS(null, "style", "fill:red");
// attach the rectangle to the svg root element
topLevelElt.appendChild(rectangle);
svgCanvas.setSVGDocument((SVGDocument)svgDocument);
}
public void doUserLoop(){
BufferedReader stdin = new BufferedReader(new
InputStreamReader(System.in));
System.err.println("do user loop");
try{
addSomeText();
while(true){
String res = stdin.readLine();
if(res.equals("c")){
clearGraph();
} else {
addSomeText();
}
}
} catch (IOException ioe){
System.err.println("IOException");
}
}
private void clearGraph(){
svgCanvas.getUpdateManager().getUpdateRunnableQueue().invokeLater(new
Runnable(){
public void run(){
NodeList children = topLevelElt.getChildNodes();
if(children != null){
int numC = children.getLength();
System.err.println("num children: " + numC);
for(int i = 0; i < numC; i++){
System.err.println(i);
System.err.println("removing: " +
children.item(0).getNodeName());
topLevelElt.removeChild(children.item(0));
System.err.println("removed");
}
}
}
});
}
private void addSomeText(){
svgCanvas.getUpdateManager().getUpdateRunnableQueue().invokeLater(new
Runnable(){
public void run(){
System.err.println("Adding text");
Element newTextElt =
svgDocument.createElementNS(svgNS, "text");
newTextElt.setAttributeNS(null, "x", "300");
newTextElt.setAttributeNS(null, "y", "200");
newTextElt.appendChild(svgDocument.createTextNode("Hello monkeys"));
System.err.println("Appending");
topLevelElt.appendChild(newTextElt);
System.err.println("Appended");
System.err.println("Added text");
}
});
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-users-help@xml.apache.org
Re: Object retention when using removeChild
Posted by Thomas DeWeese <Th...@Kodak.com>.
Hi Daniel.
Spasojevic, Daniel wrote:
>Firstly, I think that the Batik SVG toolkit is very good, and I have been very impressed with the overall quality and number of features implemented.
>
Thanks.
>
>I am having trouble removing nodes from a SVG document that has been
>associated with a JSVGCanvas object. The problem is that although calling removeChild() stops the nodes from being displayed, it seems that the objects associated with that node are retained - preventing the removed nodes from being garbage collected. I am using Batik 1.5, the problem appears when using 1.4.1_02 and 1.4.1_03 of Java, and under Windows 2000 and KDE on linux.
>
Which Batik 1.5? Beta 5?
>Hopefully this is due to a coding error on my part.
>
>
One can always hope :) However I think/know there is a memory leak
here, I have found
and fixed at least one based on your information already.
>I wrote a simple test program that built a SVG document that included a text element, associated it with a JSVGCanvas, then removed all child nodes of the document root. Using JProfiler, I found the following references to associated SVGOMTextElement (the format of this output is: name of the referant, number of references, total size of references):
>
>
Thanks for taking the time to do this. Good tests help a _lot_ I
unfortuantely do not
have access to JProfiler. Are you up for working through this with
diffs etc?
>--- Incoming references after removeChild()
>
>
I have categorized these:
Known (or strongly suspected) safe:
>field e of org.apache.batik.bridge.SVGTextElementBridge 1 40
>field ownerElement of org.apache.batik.dom.GenericAttr 2 80
>field parentNode of org.apache.batik.dom.GenericText 1 40
>field target of field this$0 of org.apache.batik.dom.AbstractParentNode$ChildNodes
>1 24
>field this$0 of
>org.apache.batik.dom.AbstractParentNode$ExtendedNamedNodeHashMap 1 24
>field this$0 of
>org.apache.batik.dom.AbstractParentNode$ExtendedNamedNodeHashMap 1 24
>
>
Now a known problem:
>org.apache.batik.bridge.BridgeContext$EventListenerMememto
>2 48
>
>
This class is now using SoftReferences in my local copy so it will
not keep the
object in memory. This change did not effect proper function, I still
need to add a
ReferenceQueue so we don't accumulate Mememto's. This will probably be
committed to CVS tonight.
Unknown source:
>class array content 6 784
>field value of java.util.HashTable$Entry
>1 24
>
>
I am especially baffled by the array references. The HashTable may
(or may
or may not be) harmless.
>These references are preventing the object from being garbage collected.
>After many additions and removals during the execution of my application,
>this causes a significant increase in the memory used.
>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-users-help@xml.apache.org