You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-dev@xmlgraphics.apache.org by bu...@apache.org on 2007/03/30 01:30:19 UTC

DO NOT REPLY [Bug 41988] New: - DOMScrambler torture test causes heap space OutOfMemoryError

DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG�
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=41988>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND�
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=41988

           Summary: DOMScrambler torture test causes heap space
                    OutOfMemoryError
           Product: Batik
           Version: 1.6
          Platform: PC
        OS/Version: Linux
            Status: NEW
          Severity: major
          Priority: P2
         Component: SVG DOM
        AssignedTo: batik-dev@xmlgraphics.apache.org
        ReportedBy: archie@dellroad.org


I've written a Batik torture test that loads an SVG document and makes zillions
of DOM changes. Running this test on some (but not all) SVG documents that I've
tried eventually leads to an OutOfMemoryException.

Therefore, there must be a memory leak in Batik somewhere relating to (or
triggered by) DOM manipulation.

Example of a document that triggers the memory leak:
 
http://svn.apache.org/repos/asf/xmlgraphics/batik/trunk/samples/tests/spec/linking/linkingViewBox.svg

Example of a document that doesn't seem to trigger the memory leak:
  http://www.living-pages.de/de/projects/xop/samples/tiger.svg

Here is the torture test and the little shell script I use to run it:

--------------------------------------------------------------------

import java.awt.Dimension;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import org.apache.batik.bridge.UpdateManager;
import org.apache.batik.bridge.UpdateManagerEvent;
import org.apache.batik.bridge.UpdateManagerListener;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.swing.gvt.GVTTreeRendererEvent;
import org.apache.batik.swing.gvt.GVTTreeRendererListener;
import org.apache.batik.swing.svg.GVTTreeBuilderEvent;
import org.apache.batik.swing.svg.GVTTreeBuilderListener;
import org.apache.batik.swing.svg.SVGDocumentLoaderEvent;
import org.apache.batik.swing.svg.SVGDocumentLoaderListener;
import org.apache.batik.swing.svg.SVGLoadEventDispatcherEvent;
import org.apache.batik.swing.svg.SVGLoadEventDispatcherListener;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.svg.SVGDefsElement;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGElement;
import org.w3c.dom.svg.SVGGElement;

public class DOMScrambler extends WindowAdapter implements
  SVGDocumentLoaderListener, GVTTreeBuilderListener,
  SVGLoadEventDispatcherListener, GVTTreeRendererListener,
  UpdateManagerListener {

    // Tweak these parameters to increase/decrease the torture
    public static final int SCRAMBLER_TIME = 100;           // lower = more torture
    public static final int SCRAMBLER_NUM_CHANGES = 10;     // higher = more torture

    private final Logger log = Logger.getLogger(getClass());
    private final String url;
    private final JFrame frame;
    private final JSVGCanvas canvas;
    private final Random random = new Random();
    private final ArrayList<SVGGElement> gnodes = new ArrayList<SVGGElement>();

    private SVGDocument dom;

    public abstract class RepeatingThread extends Thread {
        public void run() {
            try {
                while (true) {
                    execute();
                }
            } catch (Throwable t) {
                t.printStackTrace(System.err);
            }
        }
        protected abstract void execute();
        protected void delay(int millis) {
            try {
                Thread.sleep(millis);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public class MemoryReportingThread extends RepeatingThread {
        protected void execute() {
            Runtime runtime = Runtime.getRuntime();
            runtime.gc();
            System.out.println("MEMORY:");
            System.out.println("\tFREE:\t" + runtime.freeMemory());
            System.out.println("\tTOTAL:\t" + runtime.totalMemory());
            System.out.println("\tMAX:\t" + runtime.maxMemory());
            delay(10000);
        }
    }

    public class SleeperThread extends RepeatingThread {
        protected void execute() {
            delay(nextInt(500));
        }
    }

    public class SwingNoise extends SleeperThread {
        protected void execute() {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    delay(nextInt(20));
                }
            });
            super.execute();
        }
    }

    public class BatikNoise extends SleeperThread {
        protected void execute() {
            updateSVG(new Runnable() {
                public void run() {
                    delay(nextInt(20));
                }
            });
            super.execute();
        }
    }

    public class Scrambler extends SleeperThread {
        protected void execute() {
            updateSVG(new Runnable() {
                public void run()  {
                    for (int i = 0; i < nextInt(SCRAMBLER_NUM_CHANGES); i++)
                        scramble();
                }
            });
            delay(nextInt(SCRAMBLER_TIME));
        }
        protected void scramble() {
          tryagain:
            while (true) {
                SVGGElement g1 = gnodes.get(nextInt(gnodes.size()));
                SVGGElement g2 = gnodes.get(nextInt(gnodes.size()));
                NodeList kids1 = g1.getChildNodes();
                NodeList kids2 = g2.getChildNodes();
                if (kids1.getLength() == 0 && kids2.getLength() == 0)
                    continue;
                Element parent1 = kids1.getLength() > 0 ? g1 : g2;
                Element parent2 = parent1 == g1 ? g2 : g1;
                kids1 = parent1.getChildNodes();
                Node child = kids1.item(nextInt(kids1.getLength()));

                // Verify parent2 is not child or in child's subtree
                for (Node ancestor = parent2; ancestor != null;
                  ancestor = ancestor.getParentNode()) {
                    if (ancestor == child)
                        continue tryagain;
                }

                // Swizzle child node
                //log.debug("moving child " + child + " from " + parent1 + " to
" + parent2);
                parent1.removeChild(child);
                parent2.appendChild(child);
                break;
            }
        }
    }

    public DOMScrambler(String url) {
        this.url = url;
        frame = new JFrame("DOMScrambler: "
          + url.substring(url.lastIndexOf('/') + 1));
        canvas = new JSVGCanvas(null, true, true);
        canvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC);
        canvas.addSVGDocumentLoaderListener(this);
        canvas.addGVTTreeBuilderListener(this);
        canvas.addGVTTreeRendererListener(this);
        canvas.addSVGLoadEventDispatcherListener(this);
        canvas.addUpdateManagerListener(this);
        canvas.setFocusable(true);
        frame.addWindowListener(this);
    }

    public void go() {
        canvas.setURI(this.url);
    }

    public void cancel() {
        System.err.println("Something went wrong");
    }

    protected void updateSVG(final Runnable rable) {
        UpdateManager updateManager = canvas.getUpdateManager();
        updateManager.getUpdateRunnableQueue().invokeLater(
          new Runnable() {
            public void run() {
                try {
                    rable.run();
                } catch (Throwable t) {
                    t.printStackTrace(System.err);
                    System.exit(1);
                }
            }
        });
    }

    protected int nextInt(int bound) {
        synchronized (random) {
            return random.nextInt(bound);
        }
    }

    protected void ready() {

        // Get SVG DOM
        this.dom = canvas.getSVGDocument();

        // Locate all <g> nodes
        findGNodes(this.dom.getDocumentElement());

        // Start threads
        new MemoryReportingThread().start();
        new SleeperThread().start();
        new SleeperThread().start();
        new SleeperThread().start();
        new SwingNoise().start();
        new SwingNoise().start();
        new BatikNoise().start();
        new BatikNoise().start();
        new Scrambler().start();
    }

    private void findGNodes(Element elem) {
        if (elem instanceof SVGDefsElement)
            return;
        NodeList nodeList = elem.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node item = nodeList.item(i);
            if (item instanceof SVGGElement)
                gnodes.add((SVGGElement)item);
            if (item instanceof Element)
                findGNodes((Element)item);
        }
    }

    public void showFrame() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                frame.getContentPane().add(canvas);
                frame.pack();
                Dimension size = frame.getSize();
                Point center = GraphicsEnvironment
                  .getLocalGraphicsEnvironment().getCenterPoint();
                int x = (int)(center.getX() - size.getWidth() / 2);
                int y = (int)(center.getY() - size.getHeight() / 2);
                frame.setLocation(new Point(x, y));
                frame.setVisible(true);
                frame.toFront();
            }
        });
    }

    // SVGDocumentLoaderListener methods

    public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
        log.debug("Document loading started");
    }

    public void documentLoadingCompleted(SVGDocumentLoaderEvent e) {
        log.debug("Document loading completed");
    }

    public void documentLoadingCancelled(SVGDocumentLoaderEvent e) {
        log.debug("Document loading canceled");
    }

    public void documentLoadingFailed(SVGDocumentLoaderEvent e) {
        log.debug("Document loading failed: " + e);
        cancel();
    }

    // GVTTreeBuilderListener methods

    public void gvtBuildStarted(GVTTreeBuilderEvent e) {
        log.debug("GVT build started");
    }

    public void gvtBuildCompleted(GVTTreeBuilderEvent e) {
        log.debug("GVT build completed");
        showFrame();
    }

    public void gvtBuildCancelled(GVTTreeBuilderEvent e) {
        log.debug("GVT build canceled");
    }

    public void gvtBuildFailed(GVTTreeBuilderEvent e) {
        log.debug("GVT build failed: " + e);
        cancel();
    }

    // GVTTreeRendererListener methods

    public void gvtRenderingPrepare(GVTTreeRendererEvent e) {
        log.debug("GVT rendering preparing");
    }

    public void gvtRenderingStarted(GVTTreeRendererEvent e) {
        log.debug("GVT rendering started");
    }

    public void gvtRenderingCompleted(GVTTreeRendererEvent e) {
        log.debug("GVT rendering complete");
        ready();
    }

    public void gvtRenderingCancelled(GVTTreeRendererEvent e) {
        log.debug("GVT rendering canceled");
    }

    public void gvtRenderingFailed(GVTTreeRendererEvent e) {
        log.debug("GVT rendering failed: " + e);
        cancel();
    }

    // SVGLoadEventDispatcherListener methods

    public void svgLoadEventDispatchCancelled(SVGLoadEventDispatcherEvent e) {
        log.debug("Load event dispatch cancelled");
    }

    public void svgLoadEventDispatchCompleted(SVGLoadEventDispatcherEvent e) {
        log.debug("Load event dispatch completed");
    }

    public void svgLoadEventDispatchFailed(SVGLoadEventDispatcherEvent e) {
        log.debug("Load event dispatch failed: " + e);
    }

    public void svgLoadEventDispatchStarted(SVGLoadEventDispatcherEvent e) {
        log.debug("Load event dispatch started");
    }

    // UpdateManagerListener

    public void managerStarted(UpdateManagerEvent e) {
        log.debug("Update manager started");
    }

    public void managerSuspended(UpdateManagerEvent e) {
        log.debug("Update manager suspended");
    }

    public void managerResumed(UpdateManagerEvent e) {
        log.debug("Update manager resumed");
    }

    public void managerStopped(UpdateManagerEvent e) {
        log.debug("Update manager stopped");
    }

    public void updateStarted(UpdateManagerEvent e) {
        //log.debug("Update manager started");
    }

    public void updateCompleted(UpdateManagerEvent e) {
        //log.debug("Update manager completed");
    }

    public void updateFailed(UpdateManagerEvent e) {
        log.debug("Update manager failed: " + e);
    }

    // WindowListener methods

    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }

    public static void main(String[] args) throws Exception {
        ConsoleAppender consoleAppender = new ConsoleAppender(
          new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN),
          ConsoleAppender.SYSTEM_ERR);
        consoleAppender.setThreshold(Level.DEBUG);
        BasicConfigurator.configure(consoleAppender);
        if (args.length != 1) {
            System.err.println("Usage: java DOMScrambler <file | URL>");
            System.exit(1);
        }
        File file = new File(args[0]);
        if (file.exists())
            args[0] = file.toURL().toString();
        new DOMScrambler(args[0]).go();
    }
}

--------------------------------------------------------------------

#!/bin/sh

LIBS=`build-classpath batik jakarta-commons-collections jakarta-commons-lang
jakarta-commons-logging log4j spring xerces-j2 xml-commons-apis`

set -e
mkdir -p classes
javac -d classes -classpath "${LIBS}" DOMScrambler.java
java -Xmx40m -classpath classes:"${LIBS}" DOMScrambler ${1+"$@"}

--------------------------------------------------------------------

-- 
Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-dev-help@xmlgraphics.apache.org


DO NOT REPLY [Bug 41988] - DOMScrambler torture test causes heap space OutOfMemoryError

Posted by bu...@apache.org.
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG�
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=41988>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND�
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=41988





------- Additional Comments From archie@dellroad.org  2007-04-23 13:42 -------
Created an attachment (id=20022)
 --> (http://issues.apache.org/bugzilla/attachment.cgi?id=20022&action=view)
Fix for this bug.

I think I've found the problem. The SVGTextElementBridge class must override
the dispose() method to unregister the listeners, but it was not doing this.

The attached patch fixes this particular memory leak bug for me.

NOTE however that there may be other instances of this kind of bug in the code.
The thing to do it seems would be to look for subclasses of
AbstractGraphicsNodeBridge that allocate resources in
initializeDynamicSupport()  but don't free them in dispose() (or don't override
dispose() at all).

In particular, does SVG12TextElementBridge have this same bug?


-- 
Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-dev-help@xmlgraphics.apache.org


DO NOT REPLY [Bug 41988] - DOMScrambler torture test causes heap space OutOfMemoryError

Posted by bu...@apache.org.
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG�
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=41988>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND�
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=41988





------- Additional Comments From archie@dellroad.org  2007-04-01 10:29 -------
Here's a stack histogram (acquired via "jmap") showing the classes responsible
for the memory leak. All of these classes were increasing as the test ran and
have abnormally high instance counts. The list is sorted by memory usage per class:

Object Histogram:

Size    Count   Class description
-------------------------------------------------------

... lots of other classes ...
10128   422     java.util.LinkedList
11312   202     org.apache.batik.dom.GenericAttr
11640   485     org.apache.batik.css.engine.value.StringMap$Entry
11696   1462    java.lang.ref.ReferenceQueue$Lock
12896   87      org.apache.batik.css.engine.value.Value[]
15096   51      org.apache.batik.gvt.font.AWTGlyphGeometryCache$Entry[]
15720   393     java.util.HashMap
15984   666     sun.font.FontLineMetrics
19632   409     org.apache.batik.dom.GenericText
19968   290     java.lang.String[]
20136   839     java.util.LinkedList$Entry
20736   648     org.apache.batik.dom.util.DoublyIndexedTable$Entry
22160   1385   
org.apache.batik.bridge.SVGTextElementBridge$DOMChildNodeRemovedEventListener
22160   1385   
org.apache.batik.bridge.SVGTextElementBridge$DOMSubtreeModifiedEventListener
22640   1415    org.apache.batik.bridge.UnitProcessor$DefaultContext
22960   205     org.apache.batik.gvt.ShapeNode
32400   2025    java.lang.Integer
32664   1361    sun.font.TrueTypeFont$DirectoryEntry
33240   1385    org.apache.batik.gvt.text.AttributedCharacterSpanIterator
35040   1460    java.lang.ref.ReferenceQueue
37296   666     sun.font.CoreMetrics
45328   1446    boolean[]
46328   1410    org.apache.batik.gvt.GraphicsNode[]
52352   1636    java.awt.BasicStroke
55400   1385    org.apache.batik.gvt.renderer.StrokingTextPainter$TextRun
58064   191     * ObjArrayKlassKlass
59040   1476    java.util.WeakHashMap$Entry
62040   2585    org.apache.batik.gvt.font.AWTGVTFont
67104   1398    java.util.WeakHashMap
77136   3214    java.lang.ref.WeakReference
81360   2034    java.awt.Color
88640   1385    org.apache.batik.gvt.font.GVTLineMetrics
88640   1385    org.apache.batik.gvt.text.GlyphLayout
89504   2797    org.apache.batik.dom.events.EventListenerList$Entry
91320   1415    double[]
99720   1385    sun.font.StandardGlyphVector
99864   1387    org.apache.batik.bridge.SVGTextElementBridge
99912   398     java.util.HashMap$Entry[]
103416  4309    java.util.ArrayList
107912  1385    org.apache.batik.gvt.font.GVTGlyphMetrics[]
107992  1386    java.awt.geom.AffineTransform[]
110840  2771    java.text.AttributedString$AttributedStringIterator
112176  1398    java.util.WeakHashMap$Entry[]
115456  3608    java.lang.ref.Finalizer
121880  1385    org.apache.batik.gvt.font.AWTGVTGlyphVector
130592  4081    org.apache.batik.bridge.BridgeContext$EventListenerMememto
132992  4156    java.text.AttributedString
136672  8542    java.lang.Float
137200  3430    java.util.Hashtable
144000  6000    org.apache.batik.gvt.event.GraphicsNodeChangeEvent
157584  1407    org.apache.batik.gvt.CompositeGraphicsNode
158304  4947    java.lang.ref.SoftReference
166200  1385    org.apache.batik.gvt.TextNode
201456  2798    org.apache.batik.gvt.text.TextPaintInfo
202064  4379    java.lang.Object[]
220224  2770    java.awt.geom.Point2D$Float[]
238920  9955    java.util.HashMap$Entry
252792  3511    java.awt.Font
259248  2946    java.lang.Class
285208  3442    java.util.Hashtable$Entry[]
287152  4113    short[]
323736  4155    java.awt.Shape[]
326480  8162    org.apache.batik.bridge.BridgeContext$SoftReferenceMememto
347408  21713   org.apache.batik.gvt.font.GVTGlyphMetrics
404448  16852   java.util.Vector
462024  19251   java.lang.String
465360  8310    java.util.Vector[]
521112  21713   java.awt.font.GlyphMetrics
631392  26308   java.awt.geom.Rectangle2D$Float
674400  28100   java.util.Hashtable$Entry
707840  11060   java.awt.geom.AffineTransform
748448  23389   java.awt.geom.GeneralPath
806064  50379   java.awt.geom.Point2D$Float
866592  2455    * ConstantPoolCacheKlass
869400  21735   java.awt.geom.Rectangle2D$Double
1170248 2726    * InstanceKlassKlass
1338248 2726    * ConstantPoolKlass
1474768 19051   char[]
1588336 42517   * SymbolKlass
1610328 28645   * MethodKlass
1780632 21463   java.lang.Object[]
2297040 26531   byte[]
2621256 11208   int[]
3064456 28645   * ConstMethodKlass
13801968        28294   float[]


-- 
Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-dev-help@xmlgraphics.apache.org


DO NOT REPLY [Bug 41988] - DOMScrambler torture test causes heap space OutOfMemoryError

Posted by bu...@apache.org.
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG�
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=41988>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND�
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=41988





------- Additional Comments From archie@dellroad.org  2007-04-11 13:33 -------
Created an attachment (id=19933)
 --> (http://issues.apache.org/bugzilla/attachment.cgi?id=19933&action=view)
Patch to improve stress test

If you run the test on a slow enough computer, then updates will be added at a
rate faster than Batik can process them.

While such an "update pileup" will indeed cause a memory leak as well, that is
NOT the bug being described here - there is a memory leak even when Batik is
able to keep up with all the updates.

In any case, you can apply the attached patch to have the test program print
out the number of pending updates as it runs, so you can see how many there
are.


-- 
Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-dev-help@xmlgraphics.apache.org


DO NOT REPLY [Bug 41988] - DOMScrambler torture test causes heap space OutOfMemoryError

Posted by bu...@apache.org.
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG�
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=41988>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND�
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=41988





------- Additional Comments From archie@dellroad.org  2007-04-23 13:11 -------
I've done some further investigation...

1. This leak appears to be related to <text> nodes; <text> nodes are being
   referenced in the heap even after they are removed from the DOM.
2. Heap inspection reveals that a zillions of SVGTextElementBridge nodes are
   lying around, still registered as EventListeners on the DOM.
3. When the <text> node is directly removed from the DOM, no memory leak
   appears to occur. However, when the parent of a <text> node is removed
   from the DOM, the memory leak does occur.

In SVGTextElementBridge.java, the removeTextEventListeners() method must be
called when the node is removed from the DOM to avoid a memory leak. This
method is only ever called from handleDOMNodeRemovedEvent() (in same class).

Curent theory: handleDOMNodeRemovedEvent() is being properly called when the
<text> node is the node being removed, but not when the <text> node is a
descendant of the node being removed.

Here is the smallest input file that exhibits the bug when run with the
DOMScrambler program:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
  "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  width="200" height="200" viewBox="0 0 200 200"><g><g><text/></g></g></svg>

Note the two nested <g> elements. If you remove one of the <g> elements, the
leak does not occur (which is what led me to conclusion #3 above).

The above test input will take a long time to run out of memory. If you put a
bunch of actual text inside the <text> node then the leak will happen much
faster (as expected).



-- 
Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-dev-help@xmlgraphics.apache.org


DO NOT REPLY [Bug 41988] - DOMScrambler torture test causes heap space OutOfMemoryError

Posted by bu...@apache.org.
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG�
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=41988>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND�
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=41988


cam@apache.org changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |FIXED




------- Additional Comments From cam@apache.org  2007-09-25 20:13 -------
Hi Archie.

Thanks for looking into this.  You are right in that SVGTextElementBridge needs
to remove its event listeners regardless of how the element is removed from the
document.  I could not reproduce the OOME using the small test document you
provided (the listeners that are added in
SVGTextElementBridge.addTextEventListeners() are stored in a SoftReference cache
by the ctx.storeEventListenerNS() calls, and this was sufficient for them to be
cleared when memory filled up).  However, the linkingViewBox.svg document did
cause the OOME.

I've applied a similar fix to the one you provided.

> In particular, does SVG12TextElementBridge have this same bug?

It would have, since it inherits the bug from SVGTextElementBridge.

-- 
Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-dev-help@xmlgraphics.apache.org


DO NOT REPLY [Bug 41988] - DOMScrambler torture test causes heap space OutOfMemoryError

Posted by bu...@apache.org.
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG�
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=41988>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND�
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=41988


archie@dellroad.org changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Version|1.6                         |1.7




------- Additional Comments From archie@dellroad.org  2007-04-01 07:48 -------
I tried this test on Batik 1.7beta1 and the bug is still present in that version.


-- 
Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-dev-help@xmlgraphics.apache.org