> On Aug 11, 2025, at 9:44 AM, Steven Schlansker <stevenschlans...@gmail.com> > wrote: > >> >> On Aug 10, 2025, at 2:29 PM, Johannes Döbler <j...@civilian-framework.org> >> wrote: >> >> Hi Steven, >> >> I think you are onto something. Given this example >> >>> public class TypeParamsDemo { >>> public static void main(String[] args) throws Exception { >>> Method method = TypeParamsDemo.class.getMethod("getList", Set.class); >>> TypeVariable<Method>[] tp = method.getTypeParameters(); >>> } >>> >>> public <T extends Number> List<T> getList(Set<T> set) { >>> return new ArrayList<>(set); >>> } >>> } >> >> Then: >> tp[0].bounds[0].path[0].name is "java.lang.Number" and is a newly created >> String parsed from the type signature >> "<T:Ljava/lang/Number;>(Ljava/util/Set<TT;>;)Ljava/util/List<TT;>;". >> The result of method.getTypeParameters() is cached in Method.genericInfo, so >> once initialized by a caller (e.g. by Jackson/REST easy) it won't go away. >> Imho interning the class name should be fine since it refers to an existing >> class. >> >> Best >> Johannes >> > > Thank you for your analysis Johannes. > I've opened https://github.com/openjdk/jdk/pull/26730 with my proposed change. >
It seems that I need a bug issue open in order to proceed any further. Is anyone able to create a bug report and potentially sponsor this change? Thank you! Steven >> >> On 09/08/2025 01:10, Steven Schlansker wrote: >>> Hello core-libs-dev, happy Friday! >>> >>> While diagnosing an out of memory situation in our application, I noticed a >>> surprising source of memory usage. >>> While this is not so severe to actually cause our OOM, it seems wasteful >>> and I thought to bring it to your attention. >>> >>> We use reflection-based technologies like Jackson JSON and RESTEasy that >>> retrieve generic type information from many of our classes. >>> Our profiler provides diagnostics of wasted space due to duplicate objects, >>> particularly Strings. >>> >>> The analysis highlights many thousands of copies of String instances >>> holding the full name of a class, e.g. "java.util.Optional" >>> or "com.mycompany.Id". The path to GC route looks like: >>> >>> String <- sun.reflect.generics.tree.SimpleClassTypeSignature <- Object[] <- >>> ArrayList <- ClassTypeSignature <- MethodTypeSignature <- MethodRepository >>> <- Method >>> >>> Seeing how these SimpleClassTypeSignature instances are created, it looks >>> like they come from the sun.reflect.generics.parser.SignatureParser which >>> calls >>> `input.substring(mark, index)`, possibly with a call to `replace('/', '.')` >>> to munge the package name. In all but the simplest of cases, this will >>> return a new String >>> for every call. >>> >>> Since this String is representing a Class name, the cardinality should by >>> its nature be very low. For each unique type, there will be many methods >>> referring to it. >>> Additionally, this generic information is lazy-loaded at most once per >>> Method object. >>> >>> Therefore, SimpleClassTypeSignature.n seems like a natural place to apply >>> String.intern(), for example changing: >>> >>> public static SimpleClassTypeSignature make(String n, >>> boolean dollar, >>> TypeArgument[] tas){ >>> return new SimpleClassTypeSignature(n, dollar, tas); >>> } >>> >>> to intern the name: >>> >>> public static SimpleClassTypeSignature make(String n, >>> boolean dollar, >>> TypeArgument[] tas){ >>> return new SimpleClassTypeSignature(n.intern(), dollar, tas); >>> } >>> >>> With any luck, maybe this can even share the same string instance as the >>> class itself uses. >>> Am I correct in thinking this would be a moderately nice improvement, for a >>> relatively cheap cost? >>> Or perhaps there's some reason this isn't a good idea? >>> >>> Thank you for your thoughts on the subject, >>> Steven