During analysis of two heapdums shared here the following issue was discovered as a hotspot that can benefit from optimization:
Performance Data
| Metric |
WITH transitive |
WITHOUT transitive |
Ratio |
| Self time (µs) |
2,233,733 |
366,222 |
6.1× |
Description
IClasspathEntry.isTest() is a default interface method that iterates over the entire getExtraAttributes() array on every invocation:
default public boolean isTest() {
for (IClasspathAttribute attribute : getExtraAttributes()) {
if (IClasspathAttribute.TEST.equals(attribute.getName()) && "true".equals(attribute.getValue()))
return true;
}
return false;
}
This method is called on every classpath entry during classpath expansion and package fragment root computation. With transitive dependencies, the number of classpath entries grows, and isTest() is called on each one — often multiple times during the same build phase. The same pattern exists for isWithoutTestCode().
Suggested Fix
Override isTest() in ClasspathEntry (the concrete implementation) to cache the result. The extra attributes are immutable after construction, so the result can be computed once and stored:
// In ClasspathEntry.java
private int cachedIsTest = -1; // -1 = not computed, 0 = false, 1 = true
@Override
public boolean isTest() {
if (cachedIsTest == -1) {
cachedIsTest = IClasspathEntry.super.isTest() ? 1 : 0;
}
return cachedIsTest == 1;
}
Alternatively, compute isTest and isWithoutTestCode in the ClasspathEntry constructor and store as boolean fields, since these are queried on almost every entry.
During analysis of two heapdums shared here the following issue was discovered as a hotspot that can benefit from optimization:
Performance Data
Description
IClasspathEntry.isTest()is adefaultinterface method that iterates over the entiregetExtraAttributes()array on every invocation:This method is called on every classpath entry during classpath expansion and package fragment root computation. With transitive dependencies, the number of classpath entries grows, and
isTest()is called on each one — often multiple times during the same build phase. The same pattern exists forisWithoutTestCode().Suggested Fix
Override
isTest()inClasspathEntry(the concrete implementation) to cache the result. The extra attributes are immutable after construction, so the result can be computed once and stored:Alternatively, compute
isTestandisWithoutTestCodein theClasspathEntryconstructor and store as boolean fields, since these are queried on almost every entry.