Description
Renier Roth opened SPR-14862 and commented
Consider Using String.intern() on the Type scanned by the Visitors. These Strings are always identical but are duplicated in Memory cause of new String() call.
Class: org.springframework.asm.Type
Line 565 & 580
example:
{CODE:linenumbers=true}
/**
-
Returns the binary name of the class corresponding to this type. This
-
method must not be used on method types.
-
@return
the binary name of the class corresponding to this type.
*/
public String getClassName() {
switch (sort) {
case VOID:
return "void";
case BOOLEAN:
return "boolean";
case CHAR:
return "char";
case BYTE:
return "byte";
case SHORT:
return "short";
case INT:
return "int";
case FLOAT:
return "float";
case LONG:
return "long";
case DOUBLE:
return "double";
case ARRAY:
StringBuilder sb = new StringBuilder(getElementType().getClassName());
for (int i = getDimensions(); i > 0; --i) {
sb.append("[]");
}
return sb.toString();
case OBJECT:
return new String(buf, off, len).replace('/', '.');
default:
return null;
}
}/**
- Returns the internal name of the class corresponding to this object or
- array type. The internal name of a class is its fully qualified name (as
- returned by Class.getName(), where '.' are replaced by '/'. This method
- should only be used for an object or array type.
@return
the internal name of the class corresponding to this object type.
*/
public String getInternalName() {
return new String(buf, off, len);
}
{CODE}
Changed to:
{CODE:linenumbers=true}
/**
-
Returns the binary name of the class corresponding to this type. This
-
method must not be used on method types.
-
@return
the binary name of the class corresponding to this type.
*/
public String getClassName() {
switch (sort) {
case VOID:
return "void";
case BOOLEAN:
return "boolean";
case CHAR:
return "char";
case BYTE:
return "byte";
case SHORT:
return "short";
case INT:
return "int";
case FLOAT:
return "float";
case LONG:
return "long";
case DOUBLE:
return "double";
case ARRAY:
StringBuilder sb = new StringBuilder(getElementType().getClassName());
for (int i = getDimensions(); i > 0; --i) {
sb.append("[]");
}
return sb.toString();
case OBJECT:
return new String(buf, off, len).replace('/', '.').intern();
default:
return null;
}
}/**
- Returns the internal name of the class corresponding to this object or
- array type. The internal name of a class is its fully qualified name (as
- returned by Class.getName(), where '.' are replaced by '/'. This method
- should only be used for an object or array type.
@return
the internal name of the class corresponding to this object type.
*/
public String getInternalName() {
return new String(buf, off, len).intern();
}
{CODE}
Lines difference in 34 & 49
This is used by several visitors on Class/Annotation scanning. The names of these Classes are then cached, but uses a new String Reference in Memory.
By Using String.intern() we can avoid duplicated Strings.
Memory Consumption and count of duplicated Strings depends on How many Annotations you have in your managed Beans.
Affects: 4.3.3
Issue Links:
- Upgrade to ASM 5.2 [SPR-15071] #19637 Upgrade to ASM 5.2
- Use String.intern() for Class reading [SPR-14886] #19452 Use String.intern() for Class reading