[ https://issues.apache.org/jira/browse/XALANJ-2439?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12581515#action_12581515 ]
Helge Schulz commented on XALANJ-2439: -------------------------------------- Here is my patch: Index: org/apache/xalan/xsltc/dom/SAXImpl.java =================================================================== --- org/apache/xalan/xsltc/dom/SAXImpl.java (revision 640381) +++ org/apache/xalan/xsltc/dom/SAXImpl.java (working copy) @@ -1836,6 +1836,11 @@ initSize, m_buildIdIndex); } } + + public void release() + { + _dtmManager.release(this, true); + } /** * %HZ% Need Javadoc Index: org/apache/xalan/xsltc/dom/DOMAdapter.java =================================================================== --- org/apache/xalan/xsltc/dom/DOMAdapter.java (revision 640381) +++ org/apache/xalan/xsltc/dom/DOMAdapter.java (working copy) @@ -463,4 +463,9 @@ public Hashtable getElementsWithIDs() { return _dom.getElementsWithIDs(); } + + public void release() { + _dom.release(); + } + } Index: org/apache/xalan/xsltc/dom/SimpleResultTreeImpl.java =================================================================== --- org/apache/xalan/xsltc/dom/SimpleResultTreeImpl.java (revision 640381) +++ org/apache/xalan/xsltc/dom/SimpleResultTreeImpl.java (working copy) @@ -1015,4 +1015,13 @@ public void migrateTo(DTMManager manager) { } + + public void release() + { + if (_documentID != 0) { + _dtmManager.release(this, true); + _documentID = 0; + } + } + } Index: org/apache/xalan/xsltc/dom/AdaptiveResultTreeImpl.java =================================================================== --- org/apache/xalan/xsltc/dom/AdaptiveResultTreeImpl.java (revision 640381) +++ org/apache/xalan/xsltc/dom/AdaptiveResultTreeImpl.java (working copy) @@ -1316,5 +1316,14 @@ super.documentRelease(); } } + + public void release() + { + if (_dom != null) { + _dom.release(); + _dom = null; + } + super.release(); + } } Index: org/apache/xalan/xsltc/dom/MultiDOM.java =================================================================== --- org/apache/xalan/xsltc/dom/MultiDOM.java (revision 640381) +++ org/apache/xalan/xsltc/dom/MultiDOM.java (working copy) @@ -280,6 +280,58 @@ public int addDOMAdapter(DOMAdapter adapter) { return addDOMAdapter(adapter, true); } + + private boolean isMatchingAdapterEntry(DOM entry, DOMAdapter adapter) { + DOM dom = adapter.getDOMImpl(); + + return (entry == adapter) || ( + + /* + * Method addDOMAdapter overwrites for AdaptiveResultTreeImpl + * objects the usual entry with an adapter to the nested + * DOM, so we must check this here. See last 'if' statement + * of addDOMAdapter. + */ + + (dom instanceof AdaptiveResultTreeImpl) && + (entry instanceof DOMAdapter) && + (((AdaptiveResultTreeImpl) dom).getNestedDOM() + == ((DOMAdapter) entry).getDOMImpl()) + ); + } + + public void removeDOMAdapter(DOMAdapter adapter) { + _documents.remove(adapter.getDocumentURI(0)); + DOM dom = adapter.getDOMImpl(); + + if (dom instanceof DTMDefaultBase) { + SuballocatedIntVector ids = ((DTMDefaultBase) dom).getDTMIDs(); + int idsSize = ids.size(); + for (int i = 0; i < idsSize; i++) { + _adapters[ids.elementAt(i) >>> DTMManager.IDENT_DTM_NODE_BITS] = null; + } + } else { + int id = dom.getDocument() >>> DTMManager.IDENT_DTM_NODE_BITS; + if ((id > 0) && + (id < _adapters.length) && + isMatchingAdapterEntry(_adapters[id], adapter)) { + _adapters[id] = null; + } else { + boolean found = false; + + for (int i = 0; i < _adapters.length; i++) { + if (isMatchingAdapterEntry(_adapters[id], adapter)) { + _adapters[i] = null; + found = true; + } + } + if (!found) { + System.err.println("Warning: Memory leak in" + + " MultiDOM.removeDOMAdapter (adapter not found)."); + } + } + } + } private int addDOMAdapter(DOMAdapter adapter, boolean indexByURI) { // Add the DOM adapter to the array of DOMs @@ -662,4 +714,9 @@ public Hashtable getElementsWithIDs() { return _main.getElementsWithIDs(); } + + public void release() { + _main.release(); + } + } Index: org/apache/xalan/xsltc/DOM.java =================================================================== --- org/apache/xalan/xsltc/DOM.java (revision 640381) +++ org/apache/xalan/xsltc/DOM.java (working copy) @@ -102,4 +102,5 @@ public int getDocument(); public String getUnparsedEntityURI(String name); public Hashtable getElementsWithIDs(); + public void release(); } Index: org/apache/xalan/xsltc/compiler/WithParam.java =================================================================== --- org/apache/xalan/xsltc/compiler/WithParam.java (revision 640381) +++ org/apache/xalan/xsltc/compiler/WithParam.java (working copy) @@ -22,9 +22,14 @@ package org.apache.xalan.xsltc.compiler; import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.ALOAD; +import org.apache.bcel.generic.ASTORE; +import org.apache.bcel.generic.CHECKCAST; +import org.apache.bcel.generic.INVOKEINTERFACE; import org.apache.bcel.generic.INVOKEVIRTUAL; import org.apache.bcel.generic.InstructionList; import org.apache.bcel.generic.PUSH; +import org.apache.bcel.generic.LocalVariableGen; import org.apache.xalan.xsltc.compiler.util.ClassGenerator; import org.apache.xalan.xsltc.compiler.util.ErrorMsg; import org.apache.xalan.xsltc.compiler.util.MethodGenerator; @@ -56,6 +61,12 @@ * Parameter's default value. */ private Expression _select; + + /** + * Reference to JVM variable with temporary result tree, which + * must be released after template call. + */ + private LocalVariableGen _local; /** * %OPT% This is set to true when the WithParam is used in a CallTemplate @@ -155,7 +166,10 @@ * a 'select' attribute, or in the with-param element's body */ public void translateValue(ClassGenerator classGen, - MethodGenerator methodGen) { + MethodGenerator methodGen) { + final ConstantPoolGen cpg = classGen.getConstantPool(); + final InstructionList il = methodGen.getInstructionList(); + // Compile expression is 'select' attribute if present if (_select != null) { _select.translate(classGen, methodGen); @@ -164,11 +178,16 @@ // If not, compile result tree from parameter body if present. else if (hasContents()) { compileResultTree(classGen, methodGen); + + // store result tree into local variable to release them later + + _local = methodGen.addLocalVariable2("@" + _escapedName, + Type.ResultTree.toJCType(), il.getEnd()); + il.append(DUP); + il.append(new ASTORE(_local.getIndex())); } // If neither are present then store empty string in parameter slot else { - final ConstantPoolGen cpg = classGen.getConstantPool(); - final InstructionList il = methodGen.getInstructionList(); il.append(new PUSH(cpg, Constants.EMPTYSTRING)); } } @@ -206,4 +225,30 @@ ADD_PARAMETER_SIG))); il.append(POP); // cleanup stack } + + public void unmap(ClassGenerator classGen, MethodGenerator methodGen) { + if (_local != null) { + // System.out.println("WithParam.unmap: index=" + _local.getIndex()); + final InstructionList il = methodGen.getInstructionList(); + + if (classGen.getStylesheet().callsNodeset() && + classGen.getDOMClass().equals(MULTI_DOM_CLASS)) { + final int removeCNI = classGen.getConstantPool().addMethodref( + MULTI_DOM_CLASS, "removeDOMAdapter", + "(" + DOM_ADAPTER_SIG + ")V"); + + il.append(methodGen.loadDOM()); + il.append(new CHECKCAST(classGen.getConstantPool().addClass(MULTI_DOM_CLASS))); + il.append(new ALOAD(_local.getIndex())); + il.append(new CHECKCAST(classGen.getConstantPool().addClass(DOM_ADAPTER_CLASS))); + il.append(new INVOKEVIRTUAL(removeCNI)); + } + final int releaseCNI = classGen.getConstantPool().addInterfaceMethodref( + DOM_IMPL_CLASS, "release", "()V"); + + il.append(new ALOAD(_local.getIndex())); + il.append(new INVOKEINTERFACE(releaseCNI, 1)); + _local = null; + } + } } Index: org/apache/xalan/xsltc/compiler/SyntaxTreeNode.java =================================================================== --- org/apache/xalan/xsltc/compiler/SyntaxTreeNode.java (revision 640381) +++ org/apache/xalan/xsltc/compiler/SyntaxTreeNode.java (working copy) @@ -524,7 +524,7 @@ for (int i = 0; i < n; i++) { if( _contents.elementAt(i) instanceof VariableBase) { final VariableBase var = (VariableBase)_contents.elementAt(i); - var.unmapRegister(methodGen); + var.unmapRegister(classGen, methodGen); } } } Index: org/apache/xalan/xsltc/compiler/ApplyTemplates.java =================================================================== --- org/apache/xalan/xsltc/compiler/ApplyTemplates.java (revision 640381) +++ org/apache/xalan/xsltc/compiler/ApplyTemplates.java (working copy) @@ -189,7 +189,17 @@ _functionName, applyTemplatesSig); il.append(new INVOKEVIRTUAL(applyTemplates)); + + // unmap parameters to release temporary result trees + final Enumeration childs = getContents().elements(); + while (childs.hasMoreElements()) { + final Object child = childs.nextElement(); + if (child instanceof WithParam) { + ((WithParam) child).unmap(classGen, methodGen); + } + } + // Pop parameter frame if (stylesheet.hasLocalParams() || hasContents()) { il.append(classGen.loadTranslet()); Index: org/apache/xalan/xsltc/compiler/VariableBase.java =================================================================== --- org/apache/xalan/xsltc/compiler/VariableBase.java (revision 640381) +++ org/apache/xalan/xsltc/compiler/VariableBase.java (working copy) @@ -26,7 +26,10 @@ import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.Instruction; import org.apache.bcel.generic.InstructionList; +import org.apache.bcel.generic.CHECKCAST; +import org.apache.bcel.generic.INVOKEINTERFACE; import org.apache.bcel.generic.INVOKESPECIAL; +import org.apache.bcel.generic.INVOKEVIRTUAL; import org.apache.bcel.generic.LocalVariableGen; import org.apache.bcel.generic.NEW; import org.apache.bcel.generic.PUSH; @@ -34,6 +37,7 @@ import org.apache.xalan.xsltc.compiler.util.ErrorMsg; import org.apache.xalan.xsltc.compiler.util.MethodGenerator; import org.apache.xalan.xsltc.compiler.util.NodeSetType; +import org.apache.xalan.xsltc.compiler.util.ResultTreeType; import org.apache.xalan.xsltc.compiler.util.Type; import org.apache.xalan.xsltc.compiler.util.Util; import org.apache.xml.utils.XML11Char; @@ -96,12 +100,35 @@ * Remove the mapping of this variable to a register. * Called when we leave the AST scope of the variable's declaration */ - public void unmapRegister(MethodGenerator methodGen) { - if (_local != null) { - _local.setEnd(methodGen.getInstructionList().getEnd()); - methodGen.removeLocalVariable(_local); - _refs = null; - _local = null; + public void unmapRegister(ClassGenerator classGen, MethodGenerator methodGen) { + if (_local != null) { + if (_type instanceof ResultTreeType) { + final ConstantPoolGen cpg = classGen.getConstantPool(); + final InstructionList il = methodGen.getInstructionList(); + + if (classGen.getStylesheet().callsNodeset() && + classGen.getDOMClass().equals(MULTI_DOM_CLASS)) { + final int removeCNI = cpg.addMethodref( + MULTI_DOM_CLASS, "removeDOMAdapter", + "(" + DOM_ADAPTER_SIG + ")V"); + + il.append(methodGen.loadDOM()); + il.append(new CHECKCAST(cpg.addClass(MULTI_DOM_CLASS))); + il.append(loadInstruction()); + il.append(new CHECKCAST(cpg.addClass(DOM_ADAPTER_CLASS))); + il.append(new INVOKEVIRTUAL(removeCNI)); + } + final int releaseCNI = cpg.addInterfaceMethodref( + DOM_IMPL_CLASS, "release", "()V"); + il.append(loadInstruction()); + il.append(new INVOKEINTERFACE(releaseCNI, 1)); + } + if (_refs.isEmpty()) { + _local.setEnd(methodGen.getInstructionList().getEnd()); + methodGen.removeLocalVariable(_local); + _refs = null; + _local = null; + } } } Index: org/apache/xalan/xsltc/compiler/CallTemplate.java =================================================================== --- org/apache/xalan/xsltc/compiler/CallTemplate.java (revision 640381) +++ org/apache/xalan/xsltc/compiler/CallTemplate.java (working copy) @@ -167,7 +167,15 @@ il.append(new INVOKEVIRTUAL(cpg.addMethodref(className, methodName, methodSig.toString()))); - + + // unmap parameters to release temporary result trees + + for (int i = 0; i < _parameters.length; i++) { + if(_parameters[i] instanceof WithParam) { + ((WithParam) _parameters[i]).unmap(classGen, methodGen); + } + } + // Do not need to call Translet.popParamFrame() if we are // calling a simple named template. if (_calleeTemplate == null && (stylesheet.hasLocalParams() || hasContents())) { > [PATCH] XSLTC resource leak causes 'No more DTM IDs are available' error > ------------------------------------------------------------------------ > > Key: XALANJ-2439 > URL: https://issues.apache.org/jira/browse/XALANJ-2439 > Project: XalanJ2 > Issue Type: Bug > Components: XSLTC > Affects Versions: The Latest Development Code > Environment: Linux and Windows XP with Sun JRE 1.5.0_15 and 1.6.0_05 > Reporter: Helge Schulz > Priority: Minor > Fix For: The Latest Development Code > > Original Estimate: 4h > Remaining Estimate: 4h > > The Xalan XSLT compiler (XSLTC) has several resource leaks in handling > result tree fragments in XSLT variables and parameters. If a variable > or parameter declaration contains XML elements, a new DOM tree is created > and a new internal integer id is reserved for it. The garbage collector can > never retrieve this DOM tree, because the id registration holds a reference > to it. This bug prevents the transformation of large input files, because > complex templates creates many result tree fragments and exceeds often the > absolute limit of possible DOM trees in XSLTC (2^16 = 65535). If this > limit is reached, XSLTC throws the following exception: > DTMException: No more DTM IDs are available > The attached patch adds a new release method to the DOM interface and calls > it, when the scope of a variable or parameter is leaved. > You can test this patch with the attached JAR file. This file can be > called with > java -Xmx800M -jar DOMLeak-XSLT-Test-X.Y.jar > This file contains four test style sheets with expected output files. > This bug exists also in *all* Sun JRE 1.5 and 1.6 versions, because the > Xalan XSLTC source code is used in the 'com.sun.org.apache.xalan.internal' > packages. The attached test JAR file contains also a patch for the current > Sun JRE version 1.6.0_5 and a fix JAR file to be installed into the > '../jre/lib/endorsed' directory of the JRE installation. > Please add the attached test files to the Xalan test suite. I have > released them under Apache license version 2.0. > Helge Schulz - http://OpenSHORE.org > ---------- > Here is the output of running my test cases with several Java version: > test: > apply-with-all-versions: > [apply] Buildfile: build.xml > [apply] test-java: > [apply] [echo] Test Sun Java 1.4.2_17 with integrated XSLT > [apply] [java] Testing DOMLeak-1-ResultTreeInVariable.xsl... Ok. > [apply] [java] Testing DOMLeak-2-ResultTreeInCallParameter.xsl... > Ok. > [apply] [java] Testing > DOMLeak-3-ResultTreeInApplyParameter.xsl... Ok. > [apply] [java] Testing DOMLeak-4-NodeSetAndMultiDOM.xsl... Ok. > [apply] [echo] > [apply] [echo] Test Sun Java 1.4.2_17 with latest Xalan (SVN > revision 584164) > [apply] [java] Testing DOMLeak-1-ResultTreeInVariable.xsl... > ERROR: 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [java] Testing DOMLeak-2-ResultTreeInCallParameter.xsl... > ERROR: 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [java] Testing > DOMLeak-3-ResultTreeInApplyParameter.xsl... ERROR: 'No more DTM IDs are > available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [java] Testing DOMLeak-4-NodeSetAndMultiDOM.xsl... ERROR: > 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [echo] > [apply] [echo] Test Sun Java 1.4.2_17 with fixed Xalan > [apply] [java] Testing DOMLeak-1-ResultTreeInVariable.xsl... Ok. > [apply] [java] Testing DOMLeak-2-ResultTreeInCallParameter.xsl... > Ok. > [apply] [java] Testing > DOMLeak-3-ResultTreeInApplyParameter.xsl... Ok. > [apply] [java] Testing DOMLeak-4-NodeSetAndMultiDOM.xsl... Ok. > [apply] BUILD SUCCESSFUL > [apply] Total time: 1 minute 21 seconds > [apply] Buildfile: build.xml > [apply] test-java: > [apply] [echo] Test Sun Java 1.5.0_15 with integrated XSLT > [apply] [java] Testing DOMLeak-1-ResultTreeInVariable.xsl... > ERROR: 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > com.sun.org.apache.xml.internal.dtm.DTMException: No more DTM IDs are > available > [apply] [java] Testing DOMLeak-2-ResultTreeInCallParameter.xsl... > ERROR: 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > com.sun.org.apache.xml.internal.dtm.DTMException: No more DTM IDs are > available > [apply] [java] Testing > DOMLeak-3-ResultTreeInApplyParameter.xsl... ERROR: 'No more DTM IDs are > available' > [apply] [java] XSLT Exception: > com.sun.org.apache.xml.internal.dtm.DTMException: No more DTM IDs are > available > [apply] [java] Testing DOMLeak-4-NodeSetAndMultiDOM.xsl... ERROR: > 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > com.sun.org.apache.xml.internal.dtm.DTMException: No more DTM IDs are > available > [apply] [echo] > [apply] [echo] Test Sun Java 1.5.0_15 with latest Xalan (SVN > revision 584164) > [apply] [java] Testing DOMLeak-1-ResultTreeInVariable.xsl... > ERROR: 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [java] Testing DOMLeak-2-ResultTreeInCallParameter.xsl... > ERROR: 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [java] Testing > DOMLeak-3-ResultTreeInApplyParameter.xsl... ERROR: 'No more DTM IDs are > available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [java] Testing DOMLeak-4-NodeSetAndMultiDOM.xsl... ERROR: > 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [echo] > [apply] [echo] Test Sun Java 1.5.0_15 with fixed Xalan > [apply] [java] Testing DOMLeak-1-ResultTreeInVariable.xsl... Ok. > [apply] [java] Testing DOMLeak-2-ResultTreeInCallParameter.xsl... > Ok. > [apply] [java] Testing > DOMLeak-3-ResultTreeInApplyParameter.xsl... Ok. > [apply] [java] Testing DOMLeak-4-NodeSetAndMultiDOM.xsl... Ok. > [apply] BUILD SUCCESSFUL > [apply] Total time: 2 minutes 13 seconds > [apply] Buildfile: build.xml > [apply] test-java: > [apply] [echo] Test Sun Java 1.6.0_05 with integrated XSLT > [apply] [java] Testing DOMLeak-1-ResultTreeInVariable.xsl... > ERROR: 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > com.sun.org.apache.xml.internal.dtm.DTMException: No more DTM IDs are > available > [apply] [java] Testing DOMLeak-2-ResultTreeInCallParameter.xsl... > ERROR: 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > com.sun.org.apache.xml.internal.dtm.DTMException: No more DTM IDs are > available > [apply] [java] Testing > DOMLeak-3-ResultTreeInApplyParameter.xsl... ERROR: 'No more DTM IDs are > available' > [apply] [java] XSLT Exception: > com.sun.org.apache.xml.internal.dtm.DTMException: No more DTM IDs are > available > [apply] [java] Testing DOMLeak-4-NodeSetAndMultiDOM.xsl... ERROR: > 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > com.sun.org.apache.xml.internal.dtm.DTMException: No more DTM IDs are > available > [apply] [echo] > [apply] [echo] Test Sun Java 1.6.0_05 with latest Xalan (SVN > revision 584164) > [apply] [java] Testing DOMLeak-1-ResultTreeInVariable.xsl... > ERROR: 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [java] Testing DOMLeak-2-ResultTreeInCallParameter.xsl... > ERROR: 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [java] Testing > DOMLeak-3-ResultTreeInApplyParameter.xsl... ERROR: 'No more DTM IDs are > available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [java] Testing DOMLeak-4-NodeSetAndMultiDOM.xsl... ERROR: > 'No more DTM IDs are available' > [apply] [java] XSLT Exception: > org.apache.xml.dtm.DTMException: No more DTM IDs are available > [apply] [echo] > [apply] [echo] Test Sun Java 1.6.0_05 with fixed Xalan > [apply] [java] Testing DOMLeak-1-ResultTreeInVariable.xsl... Ok. > [apply] [java] Testing DOMLeak-2-ResultTreeInCallParameter.xsl... > Ok. > [apply] [java] Testing > DOMLeak-3-ResultTreeInApplyParameter.xsl... Ok. > [apply] [java] Testing DOMLeak-4-NodeSetAndMultiDOM.xsl... Ok. > [apply] BUILD SUCCESSFUL > [apply] Total time: 1 minute 42 seconds > BUILD SUCCESSFUL > Total time: 5 minutes 22 seconds -- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]