This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 7.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/7.0.x by this push: new 25b1c2c Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63236 25b1c2c is described below commit 25b1c2c5b98d5cc2581a8a35249b2796558586be Author: Mark Thomas <ma...@apache.org> AuthorDate: Thu Mar 7 19:36:43 2019 +0000 Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63236 Use intern() as suggested by Phillip Webb to reduce memory wasted due to string duplication. Saves ~254k on a clean install. Thanks to YourKit for helping to track these down. --- .../apache/catalina/util/LifecycleMBeanBase.java | 2 +- .../tomcat/util/digester/CallMethodRule.java | 2 +- java/org/apache/tomcat/util/digester/Digester.java | 233 ++++++++++----------- .../apache/tomcat/util/modeler/ManagedBean.java | 50 ++--- .../MbeansDescriptorsIntrospectionSource.java | 4 +- webapps/docs/changelog.xml | 7 + 6 files changed, 150 insertions(+), 148 deletions(-) diff --git a/java/org/apache/catalina/util/LifecycleMBeanBase.java b/java/org/apache/catalina/util/LifecycleMBeanBase.java index 2939d92..4ff80d5 100644 --- a/java/org/apache/catalina/util/LifecycleMBeanBase.java +++ b/java/org/apache/catalina/util/LifecycleMBeanBase.java @@ -238,7 +238,7 @@ public abstract class LifecycleMBeanBase extends LifecycleBase this.mserver = server; this.oname = name; - this.domain = name.getDomain(); + this.domain = name.getDomain().intern(); return oname; } diff --git a/java/org/apache/tomcat/util/digester/CallMethodRule.java b/java/org/apache/tomcat/util/digester/CallMethodRule.java index 4350ecc..8da692a 100644 --- a/java/org/apache/tomcat/util/digester/CallMethodRule.java +++ b/java/org/apache/tomcat/util/digester/CallMethodRule.java @@ -404,7 +404,7 @@ public class CallMethodRule extends Rule { throws Exception { if (paramCount == 0) { - this.bodyText = bodyText.trim(); + this.bodyText = bodyText.trim().intern(); } } diff --git a/java/org/apache/tomcat/util/digester/Digester.java b/java/org/apache/tomcat/util/digester/Digester.java index dc92d90..f427b5b 100644 --- a/java/org/apache/tomcat/util/digester/Digester.java +++ b/java/org/apache/tomcat/util/digester/Digester.java @@ -5,15 +5,15 @@ * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ + */ package org.apache.tomcat.util.digester; @@ -200,12 +200,12 @@ public class Digester extends DefaultHandler2 { * in the input is entered, the matching rules are pushed onto this * stack. After the end tag is reached, the matches are popped again. * The depth of is stack is therefore exactly the same as the current - * "nesting" level of the input xml. + * "nesting" level of the input xml. * * @since 1.6 */ protected ArrayStack<List<Rule>> matches = new ArrayStack<List<Rule>>(10); - + /** * The class loader to use for instantiating application objects. * If not specified, the context class loader, or the class loader @@ -225,7 +225,7 @@ public class Digester extends DefaultHandler2 { * The EntityResolver used by the SAX parser. By default it use this class */ protected EntityResolver entityResolver; - + /** * The URLs of entityValidator that have been registered, keyed by the public * identifier that corresponds. @@ -341,7 +341,7 @@ public class Digester extends DefaultHandler2 { */ protected boolean rulesValidation = false; - + /** * Fake attributes map (attributes are often used for object creation). */ @@ -360,12 +360,12 @@ public class Digester extends DefaultHandler2 { */ protected Log saxLog = LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax"); - - + + /** Stacks used for interrule communication, indexed by name String */ private HashMap<String,ArrayStack<Object>> stacksByName = new HashMap<String,ArrayStack<Object>>(); - + // ------------------------------------------------------------- Properties /** @@ -376,7 +376,7 @@ public class Digester extends DefaultHandler2 { * @param prefix Prefix to look up */ public String findNamespaceURI(String prefix) { - + ArrayStack<String> stack = namespaces.get(prefix); if (stack == null) { return (null); @@ -480,9 +480,9 @@ public class Digester extends DefaultHandler2 { /** * Return the SAXParserFactory we will use, creating one if necessary. - * @throws ParserConfigurationException - * @throws SAXNotSupportedException - * @throws SAXNotRecognizedException + * @throws ParserConfigurationException + * @throws SAXNotSupportedException + * @throws SAXNotRecognizedException */ public SAXParserFactory getFactory() throws SAXNotRecognizedException, SAXNotSupportedException, @@ -596,10 +596,10 @@ public class Digester extends DefaultHandler2 { * @since 1.6 */ public Log getSAXLogger() { - + return saxLog; } - + /** * Sets the logger used for logging SAX-related information. @@ -607,9 +607,9 @@ public class Digester extends DefaultHandler2 { * @param saxLog Log, not null * * @since 1.6 - */ + */ public void setSAXLogger(Log saxLog) { - + this.saxLog = saxLog; } @@ -644,7 +644,7 @@ public class Digester extends DefaultHandler2 { } - + /** * Set the public id of the current file being parse. * @param publicId the DTD/Schema public's id. @@ -652,8 +652,8 @@ public class Digester extends DefaultHandler2 { public void setPublicId(String publicId){ this.publicId = publicId; } - - + + /** * Return the public identifier of the DTD we are currently * parsing under, if any. @@ -775,7 +775,7 @@ public class Digester extends DefaultHandler2 { } - + /** * Set the <code>Rules</code> implementation object containing our * rules collection and associated matching policy. @@ -908,24 +908,24 @@ public class Digester extends DefaultHandler2 { /** * Return the XMLReader to be used for parsing the input document. * - * FIX ME: there is a bug in JAXP/XERCES that prevent the use of a + * FIX ME: there is a bug in JAXP/XERCES that prevent the use of a * parser that contains a schema with a DTD. * @exception SAXException if no XMLReader can be instantiated */ public XMLReader getXMLReader() throws SAXException { if (reader == null){ reader = getParser().getXMLReader(); - } - - reader.setDTDHandler(this); - reader.setContentHandler(this); - + } + + reader.setDTDHandler(this); + reader.setContentHandler(this); + if (entityResolver == null){ reader.setEntityResolver(this); } else { - reader.setEntityResolver(entityResolver); + reader.setEntityResolver(entityResolver); } - + reader.setProperty( "http://xml.org/sax/properties/lexical-handler", this); @@ -1031,7 +1031,7 @@ public class Digester extends DefaultHandler2 { // Parse system properties bodyText = updateBodyText(bodyText); - // the actual element name is either in localName or qName, depending + // the actual element name is either in localName or qName, depending // on whether the parser is namespace aware String name = localName; if ((name == null) || (name.length() < 1)) { @@ -1041,7 +1041,7 @@ public class Digester extends DefaultHandler2 { // Fire "body" events for all relevant rules List<Rule> rules = matches.pop(); if ((rules != null) && (rules.size() > 0)) { - String bodyText = this.bodyText.toString(); + String bodyText = this.bodyText.toString().intern(); for (int i = 0; i < rules.size(); i++) { try { Rule rule = rules.get(i); @@ -1234,7 +1234,7 @@ public class Digester extends DefaultHandler2 { saxLog.debug("startDocument()"); } - // ensure that the digester is properly configured, as + // ensure that the digester is properly configured, as // the digester could be used as a SAX ContentHandler // rather than via the parse() methods. configure(); @@ -1251,7 +1251,7 @@ public class Digester extends DefaultHandler2 { * @param qName The qualified name (with prefix), or the empty * string if qualified names are not available.\ * @param list The attributes attached to the element. If there are - * no attributes, it shall be an empty Attributes object. + * no attributes, it shall be an empty Attributes object. * @exception SAXException if a parsing error is to be reported */ @Override @@ -1259,20 +1259,20 @@ public class Digester extends DefaultHandler2 { String qName, Attributes list) throws SAXException { boolean debug = log.isDebugEnabled(); - + if (saxLog.isDebugEnabled()) { saxLog.debug("startElement(" + namespaceURI + "," + localName + "," + qName + ")"); } - + // Parse system properties list = updateAttributes(list); - + // Save the body text accumulated for our surrounding element bodyTexts.push(bodyText); bodyText = new StringBuilder(); - // the actual element name is either in localName or qName, depending + // the actual element name is either in localName or qName, depending // on whether the parser is namespace aware String name = localName; if ((name == null) || (name.length() < 1)) { @@ -1397,8 +1397,8 @@ public class Digester extends DefaultHandler2 { public void setEntityResolver(EntityResolver entityResolver){ this.entityResolver = entityResolver; } - - + + /** * Return the Entity Resolver used by the SAX parser. * @return Return the Entity Resolver used by the SAX parser. @@ -1415,27 +1415,27 @@ public class Digester extends DefaultHandler2 { saxLog.debug("resolveEntity('" + publicId + "', '" + systemId + "', '" + baseURI + "')"); } - + // Has this system identifier been registered? String entityURL = null; if (publicId != null) { entityURL = entityValidator.get(publicId); } - - if (entityURL == null) { + + if (entityURL == null) { if (systemId == null) { // cannot resolve if (log.isDebugEnabled()) { log.debug(" Cannot resolve entity: '" + publicId + "'"); } return (null); - + } else { // try to resolve using system ID if (log.isDebugEnabled()) { log.debug(" Trying to resolve using system ID '" + systemId + "'"); - } + } entityURL = systemId; // resolve systemId against baseURI if it is not absolute if (baseURI != null) { @@ -1453,12 +1453,12 @@ public class Digester extends DefaultHandler2 { } } } - + // Return an input source to our alternative URL if (log.isDebugEnabled()) { log.debug(" Resolving to alternate DTD '" + entityURL + "'"); - } - + } + try { return (new InputSource(entityURL)); } catch (Exception e) { @@ -1534,7 +1534,7 @@ public class Digester extends DefaultHandler2 { log.warn("Parse Warning Error at line " + exception.getLineNumber() + " column " + exception.getColumnNumber() + ": " + exception.getMessage(), exception); - + errorHandler.warning(exception); } @@ -1560,7 +1560,7 @@ public class Digester extends DefaultHandler2 { getXMLReader().parse(input); return (root); - } + } /** * Parse the content of the specified input source using this Digester. * Returns the root element from the object stack (if any). @@ -1571,7 +1571,7 @@ public class Digester extends DefaultHandler2 { * @exception SAXException if a parsing exception occurs */ public Object parse(InputSource input) throws IOException, SAXException { - + configure(); getXMLReader().parse(input); return (root); @@ -1641,18 +1641,18 @@ public class Digester extends DefaultHandler2 { * This must be called before the first call to <code>parse()</code>. * </p><p> * <code>Digester</code> contains an internal <code>EntityResolver</code> - * implementation. This maps <code>PUBLICID</code>'s to URLs + * implementation. This maps <code>PUBLICID</code>'s to URLs * (from which the resource will be loaded). A common use case for this - * method is to register local URLs (possibly computed at runtime by a + * method is to register local URLs (possibly computed at runtime by a * classloader) for DTDs. This allows the performance advantage of using * a local version without having to ensure every <code>SYSTEM</code> * URI on every processed xml document is local. This implementation provides * only basic functionality. If more sophisticated features are required, * using {@link #setEntityResolver} to set a custom resolver is recommended. * </p><p> - * <strong>Note:</strong> This method will have no effect when a custom - * <code>EntityResolver</code> has been set. (Setting a custom - * <code>EntityResolver</code> overrides the internal implementation.) + * <strong>Note:</strong> This method will have no effect when a custom + * <code>EntityResolver</code> has been set. (Setting a custom + * <code>EntityResolver</code> overrides the internal implementation.) * </p> * @param publicId Public identifier of the DTD to be resolved * @param entityURL The URL to use for reading this DTD @@ -1765,7 +1765,7 @@ public class Digester extends DefaultHandler2 { addRule(pattern, new CallMethodRule( methodName, - paramCount, + paramCount, paramTypes)); } @@ -1794,7 +1794,7 @@ public class Digester extends DefaultHandler2 { addRule(pattern, new CallMethodRule( methodName, - paramCount, + paramCount, paramTypes)); } @@ -1837,18 +1837,18 @@ public class Digester extends DefaultHandler2 { /** * Add a "call parameter" rule. - * This will either take a parameter from the stack - * or from the current element body text. + * This will either take a parameter from the stack + * or from the current element body text. * * @param paramIndex The zero-relative parameter number * @param fromStack Should the call parameter be taken from the top of the stack? * @see CallParamRule - */ + */ public void addCallParam(String pattern, int paramIndex, boolean fromStack) { - + addRule(pattern, new CallParamRule(paramIndex, fromStack)); - + } /** @@ -1859,16 +1859,16 @@ public class Digester extends DefaultHandler2 { * @param stackIndex set the call parameter to the stackIndex'th object down the stack, * where 0 is the top of the stack, 1 the next element down and so on * @see CallMethodRule - */ + */ public void addCallParam(String pattern, int paramIndex, int stackIndex) { - + addRule(pattern, new CallParamRule(paramIndex, stackIndex)); - + } - + /** - * Add a "call parameter" rule that sets a parameter from the current + * Add a "call parameter" rule that sets a parameter from the current * <code>Digester</code> matching path. * This is sometimes useful when using rules that support wildcards. * @@ -1879,9 +1879,9 @@ public class Digester extends DefaultHandler2 { public void addCallParamPath(String pattern,int paramIndex) { addRule(pattern, new PathCallParamRule(paramIndex)); } - + /** - * Add a "call parameter" rule that sets a parameter from a + * Add a "call parameter" rule that sets a parameter from a * caller-provided object. This can be used to pass constants such as * strings to methods; it can also be used to pass mutable objects, * providing ways for objects to do things like "register" themselves @@ -1899,15 +1899,15 @@ public class Digester extends DefaultHandler2 { * @see CallMethodRule * * @since 1.6 - */ - public void addObjectParam(String pattern, int paramIndex, + */ + public void addObjectParam(String pattern, int paramIndex, Object paramObj) { - + addRule(pattern, new ObjectParamRule(paramIndex, paramObj)); - + } - + /** * Add a "factory create" rule for the specified parameters. * Exceptions thrown during the object creation process will be propagated. @@ -2000,7 +2000,7 @@ public class Digester extends DefaultHandler2 { * @see FactoryCreateRule */ public void addFactoryCreate( - String pattern, + String pattern, String className, boolean ignoreCreateExceptions) { @@ -2021,7 +2021,7 @@ public class Digester extends DefaultHandler2 { * @see FactoryCreateRule */ public void addFactoryCreate( - String pattern, + String pattern, Class<?> clazz, boolean ignoreCreateExceptions) { @@ -2044,7 +2044,7 @@ public class Digester extends DefaultHandler2 { * @see FactoryCreateRule */ public void addFactoryCreate( - String pattern, + String pattern, String className, String attributeName, boolean ignoreCreateExceptions) { @@ -2068,7 +2068,7 @@ public class Digester extends DefaultHandler2 { * @see FactoryCreateRule */ public void addFactoryCreate( - String pattern, + String pattern, Class<?> clazz, String attributeName, boolean ignoreCreateExceptions) { @@ -2255,7 +2255,7 @@ public class Digester extends DefaultHandler2 { * @see SetPropertiesRule */ public void addSetProperties( - String pattern, + String pattern, String attributeName, String propertyName) { @@ -2274,7 +2274,7 @@ public class Digester extends DefaultHandler2 { * @see SetPropertiesRule */ public void addSetProperties( - String pattern, + String pattern, String [] attributeNames, String [] propertyNames) { @@ -2342,7 +2342,7 @@ public class Digester extends DefaultHandler2 { * Clear the current contents of the object stack. * <p> * Calling this method <i>might</i> allow another document of the same type - * to be correctly parsed. However this method was not intended for this + * to be correctly parsed. However this method was not intended for this * purpose. In general, a separate Digester object should be created for * each document to be parsed. */ @@ -2356,10 +2356,10 @@ public class Digester extends DefaultHandler2 { log = null; saxLog = null; configured = false; - + } - + public void reset() { root = null; setErrorHandler(null); @@ -2436,7 +2436,7 @@ public class Digester extends DefaultHandler2 { /** * Pushes the given object onto the stack with the given name. * If no stack already exists with the given name then one will be created. - * + * * @param stackName the name of the stack onto which the object should be pushed * @param value the Object to be pushed onto the named stack. * @@ -2456,9 +2456,9 @@ public class Digester extends DefaultHandler2 { * * <p><strong>Note:</strong> a stack is considered empty * if no objects have been pushed onto it yet.</p> - * + * * @param stackName the name of the stack from which the top value is to be popped - * @return the top <code>Object</code> on the stack or or null if the stack is either + * @return the top <code>Object</code> on the stack or or null if the stack is either * empty or has not been created yet * @throws EmptyStackException if the named stack is empty * @@ -2472,14 +2472,14 @@ public class Digester extends DefaultHandler2 { log.debug("Stack '" + stackName + "' is empty"); } throw new EmptyStackException(); - + } else { - + result = namedStack.pop(); } return result; } - + /** * <p>Gets the top object from the stack with the given name. * This method does not remove the object from the stack. @@ -2488,9 +2488,9 @@ public class Digester extends DefaultHandler2 { * if no objects have been pushed onto it yet.</p> * * @param stackName the name of the stack to be peeked - * @return the top <code>Object</code> on the stack or null if the stack is either + * @return the top <code>Object</code> on the stack or null if the stack is either * empty or has not been created yet - * @throws EmptyStackException if the named stack is empty + * @throws EmptyStackException if the named stack is empty * * @since 1.6 */ @@ -2500,11 +2500,11 @@ public class Digester extends DefaultHandler2 { if (namedStack == null ) { if (log.isDebugEnabled()) { log.debug("Stack '" + stackName + "' is empty"); - } + } throw new EmptyStackException(); - + } else { - + result = namedStack.peek(); } return result; @@ -2514,9 +2514,9 @@ public class Digester extends DefaultHandler2 { * <p>Is the stack with the given name empty?</p> * <p><strong>Note:</strong> a stack is considered empty * if no objects have been pushed onto it yet.</p> - * @param stackName the name of the stack whose emptiness + * @param stackName the name of the stack whose emptiness * should be evaluated - * @return true if the given stack if empty + * @return true if the given stack if empty * * @since 1.6 */ @@ -2528,19 +2528,19 @@ public class Digester extends DefaultHandler2 { } return result; } - + /** - * When the Digester is being used as a SAXContentHandler, + * When the Digester is being used as a SAXContentHandler, * this method allows you to access the root object that has been * created after parsing. - * + * * @return the root object that has been created after parsing * or null if the digester has not parsed any XML yet. */ public Object getRoot() { return root; } - + // ------------------------------------------------ Parameter Stack Methods @@ -2558,7 +2558,7 @@ public class Digester extends DefaultHandler2 { * <p> * <strong>Note</strong> This method may be called more than once. * Once only initialization code should be placed in {@link #initialize} - * or the code should take responsibility by checking and setting the + * or the code should take responsibility by checking and setting the * {@link #configured} flag. * </p> */ @@ -2580,19 +2580,19 @@ public class Digester extends DefaultHandler2 { configured = true; } - + /** * <p> * Provides a hook for lazy initialization of this <code>Digester</code> - * instance. + * instance. * The default implementation does nothing, but subclasses * can override as needed. * Digester (by default) only calls this method once. * </p> * * <p> - * <strong>Note</strong> This method will be called by {@link #configure} - * only when the {@link #configured} flag is false. + * <strong>Note</strong> This method will be called by {@link #configure} + * only when the {@link #configured} flag is false. * Subclasses that override <code>configure</code> or who set <code>configured</code> * may find that this method may be called more than once. * </p> @@ -2604,7 +2604,7 @@ public class Digester extends DefaultHandler2 { // Perform lazy initialization as needed // Nothing required by default - } + } // -------------------------------------------------------- Package Methods @@ -2623,7 +2623,7 @@ public class Digester extends DefaultHandler2 { * <p>Return the top object on the parameters stack without removing it. If there are * no objects on the stack, return <code>null</code>.</p> * - * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. + * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. * See {@link #params}.</p> */ public Object peekParams() { @@ -2643,7 +2643,7 @@ public class Digester extends DefaultHandler2 { * and [getCount()-1] is the bottom element. If the specified index * is out of range, return <code>null</code>.</p> * - * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. + * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. * See {@link #params}.</p> * * @param n Index of the desired element, where 0 is the top of the stack, @@ -2665,7 +2665,7 @@ public class Digester extends DefaultHandler2 { * <p>Pop the top object off of the parameters stack, and return it. If there are * no objects on the stack, return <code>null</code>.</p> * - * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. + * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. * See {@link #params}.</p> */ public Object popParams() { @@ -2686,7 +2686,7 @@ public class Digester extends DefaultHandler2 { /** * <p>Push a new object onto the top of the parameters stack.</p> * - * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. + * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. * See {@link #params}.</p> * * @param object The new object @@ -2767,7 +2767,7 @@ public class Digester extends DefaultHandler2 { public SAXException createSAXException(String message) { return createSAXException(message, null); } - + // ------------------------------------------------------- Private Methods @@ -2782,17 +2782,13 @@ public class Digester extends DefaultHandler2 { if (list.getLength() == 0) { return list; } - + AttributesImpl newAttrs = new AttributesImpl(list); int nAttributes = newAttrs.getLength(); for (int i = 0; i < nAttributes; ++i) { String value = newAttrs.getValue(i); try { - String newValue = - IntrospectionUtils.replaceProperties(value, null, source); - if (value != newValue) { - newAttrs.setValue(i, newValue); - } + newAttrs.setValue(i, IntrospectionUtils.replaceProperties(value, null, source).intern()); } catch (Exception e) { log.warn("Attribute [" + newAttrs.getLocalName(i) + "] failed to update and remains [" + value + "].", e); @@ -2800,7 +2796,6 @@ public class Digester extends DefaultHandler2 { } return newAttrs; - } diff --git a/java/org/apache/tomcat/util/modeler/ManagedBean.java b/java/org/apache/tomcat/util/modeler/ManagedBean.java index 0f2e44c..93b68b4 100644 --- a/java/org/apache/tomcat/util/modeler/ManagedBean.java +++ b/java/org/apache/tomcat/util/modeler/ManagedBean.java @@ -5,9 +5,9 @@ * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -49,7 +49,7 @@ import javax.management.ServiceNotFoundException; public class ManagedBean implements java.io.Serializable { private static final long serialVersionUID = 1L; - + private static final String BASE_MBEAN = "org.apache.tomcat.util.modeler.BaseModelMBean"; // ----------------------------------------------------- Instance Variables static final Object[] NO_ARGS_PARAM = new Object[0]; @@ -69,7 +69,7 @@ public class ManagedBean implements java.io.Serializable { private Map<String,OperationInfo> operations = new HashMap<String,OperationInfo>(); - + protected String className = BASE_MBEAN; //protected ConstructorInfo constructors[] = new ConstructorInfo[0]; protected String description = null; @@ -81,9 +81,9 @@ public class ManagedBean implements java.io.Serializable { protected NotificationInfo notifications[] = new NotificationInfo[0]; protected String type = null; - /** Constructor. Will add default attributes. - * - */ + /** Constructor. Will add default attributes. + * + */ public ManagedBean() { AttributeInfo ai=new AttributeInfo(); ai.setName("modelerType"); @@ -92,7 +92,7 @@ public class ManagedBean implements java.io.Serializable { ai.setWriteable(false); addAttribute(ai); } - + // ------------------------------------------------------------- Properties @@ -383,8 +383,8 @@ public class ManagedBean implements java.io.Serializable { clazz = Class.forName(getClassName()); } catch (Exception e) { } - - if( clazz==null ) { + + if( clazz==null ) { try { ClassLoader cl= Thread.currentThread().getContextClassLoader(); if ( cl != null) @@ -393,8 +393,8 @@ public class ManagedBean implements java.io.Serializable { ex=e; } } - - if( clazz==null) { + + if( clazz==null) { throw new MBeanException (ex, "Cannot load ModelMBean class " + getClassName()); } @@ -409,9 +409,9 @@ public class ManagedBean implements java.io.Serializable { getClassName()); } } - + mbean.setManagedBean(this); - + // Set the managed resource (if any) try { if (instance != null) @@ -471,11 +471,11 @@ public class ManagedBean implements java.io.Serializable { // Construct and return a new ModelMBeanInfo object - info = new MBeanInfo(getClassName(), + info = new MBeanInfo(getClassName(), getDescription(), - attributes, - new MBeanConstructorInfo[] {}, - operations, + attributes, + new MBeanConstructorInfo[] {}, + operations, notifications); // try { // Descriptor descriptor = info.getMBeanDescriptor(); @@ -520,7 +520,7 @@ public class ManagedBean implements java.io.Serializable { } - Method getGetter(String aname, BaseModelMBean mbean, Object resource) + Method getGetter(String aname, BaseModelMBean mbean, Object resource) throws AttributeNotFoundException, ReflectionException { Method m = null; @@ -529,7 +529,7 @@ public class ManagedBean implements java.io.Serializable { // Look up the actual operation to be used if (attrInfo == null) throw new AttributeNotFoundException(" Cannot find attribute " + aname + " for " + resource); - + String getMethod = attrInfo.getGetMethod(); if (getMethod == null) throw new AttributeNotFoundException("Cannot find attribute " + aname + " get method name"); @@ -558,7 +558,7 @@ public class ManagedBean implements java.io.Serializable { return m; } - public Method getSetter(String aname, BaseModelMBean bean, Object resource) + public Method getSetter(String aname, BaseModelMBean bean, Object resource) throws AttributeNotFoundException, ReflectionException { Method m = null; @@ -602,11 +602,11 @@ public class ManagedBean implements java.io.Serializable { return m; } - public Method getInvoke(String aname, Object[] params, String[] signature, BaseModelMBean bean, Object resource) + public Method getInvoke(String aname, Object[] params, String[] signature, BaseModelMBean bean, Object resource) throws MBeanException, ReflectionException { Method method = null; - + if (params == null) params = new Object[0]; if (signature == null) @@ -671,7 +671,7 @@ public class ManagedBean implements java.io.Serializable { } key.append(')'); - return key.toString(); + return key.toString().intern(); } @@ -686,6 +686,6 @@ public class ManagedBean implements java.io.Serializable { } key.append(')'); - return key.toString(); + return key.toString().intern(); } } diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java index c90a7a5..fa5c4d8 100644 --- a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java +++ b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java @@ -356,8 +356,8 @@ public class MbeansDescriptorsIntrospectionSource extends ModelerSource for(int i=0; i<parms.length; i++ ) { ParameterInfo pi=new ParameterInfo(); pi.setType(parms[i].getName()); - pi.setName( "param" + i); - pi.setDescription("Introspected parameter param" + i); + pi.setName(("param" + i).intern()); + pi.setDescription(("Introspected parameter param" + i).intern()); op.addParameter(pi); } mbean.addOperation(op); diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 438bc5e..f6d55d8 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -73,6 +73,13 @@ searching for nested groups when the JNDIRealm is configured with <code>roleNested</code> set to <code>true</code>. (markt) </fix> + <fix> + <bug>63236</bug>: Use <code>String.intern()</code> as suggested by + Phillip Webb to reduce memory wasted due to String duplication. This + changes saves ~245k when starting a clean installation. With additional + thanks to YourKit Java profiler for helping to track down the wasted + memory and the root causes. (markt) + </fix> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org