in application/org.openjdk.jmc.joverflow/src/main/java/org/openjdk/jmc/joverflow/stats/DetailedStatsCalculator.java [378:487]
public void handleObjectArray(JavaObjectArray objArray, JavaHeapObject[] elements) {
if (objArray.isVisitedAsCollectionImpl()) {
return;
}
numObjArrays++;
int arraySize = objArray.getSize();
totalObjArraysShallowSize += arraySize;
objArray.getClazz().updateInclusiveInstanceSize(arraySize);
boolean goodArray = true;
if (elements.length == 0) {
// goodArray = false;
CollectionClassDescriptor classDesc = colDescriptors.getStandaloneArrayDescriptor(objArray);
numLengthZeroObjArrays++;
int ovhd = arraySize;
lengthZeroObjArraysOvhd += ovhd;
classDesc.addProblematicCollection(ProblemKind.LENGTH_ZERO, ovhd);
refChain.recordCurrentRefChainForColCluster(objArray, new ArrayObjDescriptor(classDesc, 0, arraySize),
ProblemKind.LENGTH_ZERO, ovhd);
return;
}
if (elements.length == 1) {
goodArray = false;
CollectionClassDescriptor classDesc = colDescriptors.getStandaloneArrayDescriptor(objArray);
numLengthOneObjArrays++;
int ovhd = arraySize;
lengthOneObjArraysOvhd += ovhd;
classDesc.addProblematicCollection(ProblemKind.LENGTH_ONE, ovhd);
refChain.recordCurrentRefChainForColCluster(objArray, new ArrayObjDescriptor(classDesc, 0, arraySize),
ProblemKind.LENGTH_ONE, ovhd);
}
int nNullEntries = 0;
boolean boxedNumsPresent = false;
int totalBoxedNumOvhd = 0;
for (JavaHeapObject element : elements) {
if (element != null) {
int primitiveNumSize = element.getClazz().getBoxedNumberSize();
if (primitiveNumSize > 0) {
boxedNumsPresent = true;
// Below is how much memory we would save (or maybe lose) if we replace a
// pointer with the primitive type array slot
totalBoxedNumOvhd += (ptrSize - primitiveNumSize);
JavaLazyReadObject elementObj = (JavaLazyReadObject) element;
// If the same Number object is referenced from two places, don't count it twice
if (!elementObj.isVisitedAsOther()) {
elementObj.setVisitedAsOther();
totalBoxedNumOvhd += element.getSize(); // Savings from getting rid of boxed Number
}
}
} else {
nNullEntries++;
}
}
CollectionClassDescriptor classDesc = colDescriptors.getStandaloneArrayDescriptor(objArray);
ArrayObjDescriptor arrayDesc = new ArrayObjDescriptor(classDesc, elements.length, arraySize);
if (nNullEntries > elements.length / 2) {
// Empty or sparse object array dangling from something other than a known collection
goodArray = false;
if (nNullEntries == elements.length) {
numEmptyObjArrays++;
int ovhd = objArray.getSize();
emptyObjArraysOvhd += ovhd;
classDesc.addProblematicCollection(ProblemKind.EMPTY, ovhd);
refChain.recordCurrentRefChainForColCluster(objArray, arrayDesc, ProblemKind.EMPTY, ovhd);
} else {
numSparseArrays++;
int ovhd = nNullEntries * ptrSize;
sparseObjArraysOvhd += ovhd;
classDesc.addProblematicCollection(ProblemKind.SPARSE_ARRAY, ovhd);
refChain.recordCurrentRefChainForColCluster(objArray, arrayDesc, ProblemKind.SPARSE_ARRAY, ovhd);
}
}
if (boxedNumsPresent) {
numBoxedNumberArrays++;
// In extreme cases, the overhead of boxed numbers can actually be negative. For example,
// with 4-byte pointers, if we have 20 elements of Double[] array pointing at a single
// Double object, we will use 4*20 + 16 = 96 bytes. However, a double[] array of the same
// size would use 8*20 = 160 bytes. Thus we count all boxed arrays for consistency above,
// but we add up the overhead and store the details only for those where overhead is real.
if (totalBoxedNumOvhd > 0) {
goodArray = false;
boxNumObjArraysOvhd += totalBoxedNumOvhd;
classDesc.addProblematicCollection(ProblemKind.BOXED, totalBoxedNumOvhd);
refChain.recordCurrentRefChainForColCluster(objArray, arrayDesc, ProblemKind.BOXED, totalBoxedNumOvhd);
}
}
BarArrayHandler barHandler = BarArrayHandler.createInstance(elements, colDescriptors);
if (barHandler != null) {
int ovhd = barHandler.calculateOverhead();
if (ovhd > 0) {
goodArray = false;
numBarObjArrays++;
barObjArraysOvhd += ovhd;
classDesc.addProblematicCollection(ProblemKind.BAR, ovhd);
refChain.recordCurrentRefChainForColCluster(objArray, arrayDesc, ProblemKind.BAR, ovhd);
}
}
if (goodArray) { // No defects found for this array
refChain.recordCurrentRefChainForGoodCollection(objArray, arrayDesc);
}
}