Description
Christoph Dreis opened SPR-16667 and commented
Hi,
while analyzing the calls to ClassUtils.forName() in my Spring-Boot app I noticed that there might be an opportunity to optimize some more calls of commonly known classes. E.g. when looking for calls to Java classes I saw the following distribution for a total of 13000 calls (roughly 3000 coming from Java classes):
Class | Calls |
---|---|
java.lang.Cloneable | 1168 |
java.io.Serializable | 790 |
java.lang.String | 473 |
java.lang.Enum | 292 |
java.util.List | 150 |
java.lang.Object | 82 |
java.lang.Long | 74 |
java.util.Map | 52 |
java.util.Collection | 52 |
java.lang.Class | 41 |
java.util.Optional | 39 |
java.lang.Integer | 32 |
... | ... |
As you notice especially Serializable and Cloneable take up a big portion here, which are missing from the common class cache. Also Enum and the Collection framework interfaces contribute to the calls.
An isolated JMH benchmark for Serializable shows the following results:
Benchmark | Mode | Cnt | Score | Error | Units |
---|---|---|---|---|---|
MyBenchmark.testNew | thrpt | 10 | 102632276,261 | ± 37687656,076 | ops/s |
MyBenchmark.testNew: gc.alloc.rate | thrpt | 10 | 0,001 | ± 0,001 | MB/sec |
MyBenchmark.testNew: gc.alloc.rate.norm | thrpt | 10 | ? 10?? | B/op | |
MyBenchmark.testOld | thrpt | 10 | 1072135,584 | ± 38640,911 | ops/s |
MyBenchmark.testOld:·gc.alloc.rate | thrpt | 10 | 138,990 | ± 5,010 | MB/sec |
MyBenchmark.testOld:·gc.alloc.rate.norm | thrpt | 10 | 136,001 | ± 0,001 | B/op |
I understand that drawing the line is a difficult thing to do - in fact I had the same problem - but I'd argue we could add the Collection interfaces, Enum and Optional and the interfaces contained in the javaLanguageInterfaces field to the common class cache. That seems like a reasonable collection of commonly known classes.
I'd be happy to hear your opinion on the attached PR.
Cheers,
Christoph
Affects: 4.3.14, 5.0.4
Issue Links:
- Performance regression on startup (in particular in AnnotationUtils) [SPR-13621] #18199 Performance regression on startup (in particular in AnnotationUtils)
- Metadata reading should never use ASM for java.* and javax.* types (in particular on JDK 8) [SPR-11719] #16341 Metadata reading should never use ASM for java.* and javax.* types (in particular on JDK 8)
- CachedIntrospectionResults should use BeanInfoFactory when introspecting implemented interfaces [SPR-16322] #20869 CachedIntrospectionResults should use BeanInfoFactory when introspecting implemented interfaces
- Comprehensively cache annotated methods for interfaces and superclasses [SPR-16675] #21216 Comprehensively cache annotated methods for interfaces and superclasses
- Avoid unnecessary synthesizable annotation processing [SPR-16933] #21472 Avoid unnecessary synthesizable annotation processing
Referenced from: pull request #1761, and commits 4da27c2, 5d54adf, 22a8a66, 7a8d41e
Backported to: 4.3.15