in src/application/org.openjdk.jmc.joverflow/src/main/java/org/openjdk/jmc/joverflow/batch/ReportFormatter.java [212:592]
private void formatDetailedStats(
boolean printFullObjectHistogram, int printedRefChainDepth, String[] refChainStopperClassPrefixes) {
b.println(DASH_SEPARATOR);
b.startSection("2. CLASS AND OBJECT INFORMATION:", "High memory consumption by instances of", 10.0);
List<ObjectHistogram.Entry> objHistogram = hs.objHisto
.getListSortedByInclusiveSize(printFullObjectHistogram ? 0 : ds.minOvhdToReport);
b.format("\nTotal classes: %,d Total objects: %,d\n", hs.nClasses, hs.nObjects);
int[] smallInstClasses = hs.objHisto.calculateNumSmallInstClasses();
b.format("Classes with no instances: %,d Classes with 1 instance: %,d\n", smallInstClasses[0],
smallInstClasses[1]);
b.println("\nObject histogram for top memory consumers");
b.println(" #instances Shallow size Impl-inclusive size Class name");
b.println("---------------------------------------------------------------");
for (ObjectHistogram.Entry entry : objHistogram) {
b.format("%,10d %16s %16s %s\n", entry.getNumInstances(), b.k(entry.getTotalShallowSize()),
b.k(entry.getTotalInclusiveSize()), entry.getClazz().getHumanFriendlyNameWithLoaderIfNeeded());
b.criticalCheck(entry.getTotalInclusiveSize(), entry.getClazz().getHumanFriendlyNameWithLoaderIfNeeded());
}
b.println(DASH_SEPARATOR);
b.startSection("3. NUMBER, SIZE AND NEAREST FIELDS FOR HIGH MEMORY CONSUMERS:");
b.println();
List<ReferencedObjCluster.HighSizeObjects> hsFields = ds.highSizeObjClusters.get(1);
for (ReferencedObjCluster.HighSizeObjects c : hsFields) {
RefChainElement classAndField = c.getReferer();
String classAndFieldStr = ReferenceChain.toStringInStraightOrder(classAndField);
String fieldDefiningClass = getFieldDefiningClassFromFieldRefChain(
ReferenceChain.getRootElement(classAndField));
if (fieldDefiningClass != null) {
classAndFieldStr += " (defined in " + fieldDefiningClass + ")";
}
b.print(" ");
b.print(classAndFieldStr);
b.println(" -->");
b.println(c.clusterAsString(b.getMemNumFormatter()));
}
b.println(DASH_SEPARATOR);
b.startSection("4. NUMBER, SIZE AND REF CHAINS FOR TOP MEMORY CONSUMERS:");
b.println();
List<ReferencedObjCluster.HighSizeObjects> hsReverseChains = ds.highSizeObjClusters.get(0);
for (ReferencedObjCluster c : hsReverseChains) {
b.println(c.clusterAsString(b.getMemNumFormatter()));
b.print(" ");
b.println(ReferenceChain.toStringInReverseOrder(c.getReferer(), printedRefChainDepth,
refChainStopperClassPrefixes));
}
b.println(DASH_SEPARATOR);
b.startSection("5. PROBLEMATIC COLLECTIONS:", "High overhead due to problematic collections of kind", 2.0);
b.format("\nTotal collections: %,d\n", hs.numCols);
b.format("\nEmpty unused collections total number: %,10d, ovhd: %14s\n", hs.numEmptyUnusedCols,
b.k(hs.emptyUnusedColsOverhead));
b.criticalCheck(hs.emptyUnusedColsOverhead, "empty unused");
printClassesWithProblemKind(Constants.ProblemKind.EMPTY_UNUSED, false, false);
b.format("\nEmpty used collections total number: %,10d, ovhd: %14s\n", hs.numEmptyUsedCols,
b.k(hs.emptyUsedColsOverhead));
b.criticalCheck(hs.emptyUsedColsOverhead, "empty used");
printClassesWithProblemKind(Constants.ProblemKind.EMPTY_USED, false, false);
b.format("\nEmpty collections total number: %,10d, ovhd: %14s\n", hs.numEmptyCols,
b.k(hs.emptyColsOverhead));
b.criticalCheck(hs.emptyColsOverhead, "empty");
printClassesWithProblemKind(Constants.ProblemKind.EMPTY, false, false);
b.format("\nSmall sparse collections total number: %,10d, ovhd: %14s\n", hs.numSparseSmallCols,
b.k(hs.sparseSmallColsOverhead));
b.criticalCheck(hs.sparseSmallColsOverhead, "small sparse");
printClassesWithProblemKind(Constants.ProblemKind.SPARSE_SMALL, false, false);
b.format("\nLarge sparse collections total number: %,10d, ovhd: %14s\n", hs.numSparseLargeCols,
b.k(hs.sparseLargeColsOverhead));
b.criticalCheck(hs.sparseLargeColsOverhead, "large sparse");
printClassesWithProblemKind(Constants.ProblemKind.SPARSE_LARGE, false, false);
b.format("\nBoxed Number collections total number: %,10d, ovhd: %14s\n", hs.numBoxedNumberCols,
b.k(hs.boxedNumberColsOverhead));
b.criticalCheck(hs.boxedNumberColsOverhead, "boxed number");
printClassesWithProblemKind(Constants.ProblemKind.BOXED, false, false);
b.format("\nVertical bar collections total number: %,10d, ovhd: %14s\n", hs.numBarCols,
b.k(hs.barColsOverhead));
b.criticalCheck(hs.barColsOverhead, "vertical bar");
printClassesWithProblemKind(Constants.ProblemKind.BAR, false, false);
b.format("\nSmall collections total number: %,10d, ovhd: %14s\n", hs.numSmallCols,
b.k(hs.smallColsOverhead));
b.criticalCheck(hs.smallColsOverhead, "small");
printClassesWithProblemKind(Constants.ProblemKind.SMALL, false, false);
b.println(DASH_SEPARATOR);
b.startSection("6. PROBLEMATIC STANDALONE OBJECT ARRAYS:",
"High overhead due to problematic object arrays of kind", 2.0);
b.format("\nTotal standalone obj arrays: %,d\n", hs.numObjArrays);
b.format("\nLength 0 object arrays number: %,10d, ovhd: %14s\n", hs.numLengthZeroObjArrays,
b.k(hs.lengthZeroObjArraysOverhead));
b.criticalCheck(hs.lengthZeroObjArraysOverhead, "length 0");
printClassesWithProblemKind(Constants.ProblemKind.LENGTH_ZERO, true, false);
b.format("\nLength 1 object arrays number: %,10d, ovhd: %14s\n", hs.numLengthOneObjArrays,
b.k(hs.lengthOneObjArraysOverhead));
b.criticalCheck(hs.lengthOneObjArraysOverhead, "length 1");
printClassesWithProblemKind(Constants.ProblemKind.LENGTH_ONE, true, false);
b.format("\nEmpty object arrays number: %,10d, ovhd: %14s\n", hs.numEmptyObjArrays,
b.k(hs.emptyObjArraysOverhead));
b.criticalCheck(hs.emptyObjArraysOverhead, "empty");
printClassesWithProblemKind(Constants.ProblemKind.EMPTY, true, false);
b.format("\nSparse object arrays number: %,10d, ovhd: %14s\n", hs.numSparseObjArrays,
b.k(hs.sparseObjArraysOverhead));
b.criticalCheck(hs.sparseObjArraysOverhead, "sparse");
printClassesWithProblemKind(Constants.ProblemKind.SPARSE_ARRAY, true, false);
b.format("\nBoxed Number object arrays number: %,10d, ovhd: %14s\n", hs.numBoxedNumberArrays,
b.k(hs.boxedNumberArraysOverhead));
b.criticalCheck(hs.boxedNumberArraysOverhead, "boxed");
printClassesWithProblemKind(Constants.ProblemKind.BOXED, true, false);
b.format("\nVertical bar object arrays number: %,10d, ovhd: %14s\n", hs.numBarObjArrays,
b.k(hs.barObjArraysOverhead));
b.criticalCheck(hs.barObjArraysOverhead, "vertical bar");
printClassesWithProblemKind(Constants.ProblemKind.BAR, true, false);
b.println(DASH_SEPARATOR);
b.startSection("7. PROBLEMATIC STANDALONE PRIMITIVE ARRAYS:",
"High overhead due to problematic primitive arrays of kind", 2.0);
b.format("\nTotal standalone primitive arrays: %,d\n", hs.numValueArrays);
b.format("\nLength 0 primitive arrays number: %,8d, ovhd: %14s\n", hs.numLengthZeroValueArrays,
b.k(hs.lengthZeroValueArraysOverhead));
b.criticalCheck(hs.lengthZeroValueArraysOverhead, "length 0");
printClassesWithProblemKind(Constants.ProblemKind.LENGTH_ZERO, true, true);
b.format("\nLength 1 primitive arrays number: %,8d, ovhd: %14s\n", hs.numLengthOneValueArrays,
b.k(hs.lengthOneValueArraysOverhead));
b.criticalCheck(hs.lengthOneValueArraysOverhead, "length 1");
printClassesWithProblemKind(Constants.ProblemKind.LENGTH_ONE, true, true);
b.format("\nEmpty primitive arrays number: %,8d, ovhd: %14s\n", hs.numEmptyValueArrays,
b.k(hs.emptyValueArraysOverhead));
b.criticalCheck(hs.emptyValueArraysOverhead, "empty");
printClassesWithProblemKind(Constants.ProblemKind.EMPTY, true, true);
b.format("\nLong zero-tail primitive arrays number: %,8d, ovhd: %14s\n", hs.numLZTValueArrays,
b.k(hs.lztValueArraysOverhead));
b.criticalCheck(hs.lztValueArraysOverhead, "long zero-tail (LZT)");
printClassesWithProblemKind(Constants.ProblemKind.LZT, true, true);
b.format("\nUnused high bytes primitive arrays number:%,8d, ovhd: %14s\n", hs.numUnusedHiBytesValueArrays,
b.k(hs.unusedHiBytesValueArraysOverhead));
b.criticalCheck(hs.unusedHiBytesValueArraysOverhead, "unused high bytes");
printClassesWithProblemKind(Constants.ProblemKind.UNUSED_HI_BYTES, true, true);
b.println(DASH_SEPARATOR);
b.startSection("8. NUMBER, OVERHEAD AND NEAREST FIELDS FOR PROBLEMATIC COLLECTIONS AND ARRAYS:");
b.println();
List<ReferencedObjCluster.Collections> colFields = ds.collectionClusters.get(1);
for (ReferencedObjCluster.Collections c : colFields) {
if (c.getTotalOverhead() < ds.minOvhdToReport / 4) {
break;
}
RefChainElement classAndField = c.getReferer();
String classAndFieldStr = ReferenceChain.toStringInStraightOrder(classAndField);
String fieldDefiningClass = getFieldDefiningClassFromFieldRefChain(
ReferenceChain.getRootElement(classAndField));
if (fieldDefiningClass != null) {
classAndFieldStr += " (defined in " + fieldDefiningClass + ")";
}
b.print(" ");
b.print(classAndFieldStr);
b.println(" -->");
b.println(c.clusterAsString(b.getMemNumFormatter()));
}
b.println(DASH_SEPARATOR);
b.startSection("9. NUMBER, OVERHEAD AND REF CHAINS FOR PROBLEMATIC COLLECTIONS AND ARRAYS:");
b.println();
List<ReferencedObjCluster.Collections> colReverseChains = ds.collectionClusters.get(0);
for (ReferencedObjCluster c : colReverseChains) {
// For individual clusters, we set a smaller overhead threshold
if (c.getTotalOverhead() < ds.minOvhdToReport / 4) {
break;
}
b.println(c.clusterAsString(b.getMemNumFormatter()));
b.print(" ");
b.println(ReferenceChain.toStringInReverseOrder(c.getReferer(), printedRefChainDepth,
refChainStopperClassPrefixes));
}
b.println(DASH_SEPARATOR);
b.startSection("10. DUPLICATE STRING STATS:", "High overhead due to duplicate strings", 5.0);
DupStringStats dss = hs.dupStringStats;
b.format("\nTotal strings: %,d Unique strings: %,d Duplicate values: %,d Overhead: %s\n", dss.nStrings,
dss.nUniqueStringValues, dss.nUniqueDupStringValues, b.k(dss.dupStringsOverhead));
b.criticalCheck(dss.dupStringsOverhead, "");
b.format("Top duplicate Strings:\n");
b.format(" Ovhd Num char[]s Num objs Max arr len Value\n");
for (DupStringStats.Entry entry : dss.dupStrings) {
if (entry.overhead < ds.minOvhdToReport) {
break;
}
b.format("%14s %6d %6d %6d ", b.k(entry.overhead), entry.nBackingArrays,
entry.nStringInstances, entry.maxArrayLen);
String string = MiscUtils.removeEndLinesAndAddQuotes(entry.string, 100);
b.println(string);
}
b.println(DASH_SEPARATOR);
b.startSection("11. NUMBER, OVERHEAD AND NEAREST FIELDS FOR DUPLICATE STRINGS:");
b.println();
List<ReferencedObjCluster.DupStrings> rsFields = ds.dupStringClusters.get(1);
for (ReferencedObjCluster c : rsFields) {
if (c.getTotalOverhead() < ds.minOvhdToReport / 4) {
break;
}
RefChainElement classAndField = c.getReferer();
String classAndFieldStr = ReferenceChain.toStringInStraightOrder(classAndField);
String fieldDefiningClass = getFieldDefiningClassFromFieldRefChain(
ReferenceChain.getRootElement(classAndField));
if (fieldDefiningClass != null) {
classAndFieldStr += " (defined in " + fieldDefiningClass + ")";
}
b.print(" ");
b.print(classAndFieldStr);
b.println(" -->");
b.println(c.clusterAsString(b.getMemNumFormatter()));
}
b.println(DASH_SEPARATOR);
b.startSection("12. NUMBER, OVERHEAD AND REF CHAINS FOR DUPLICATE STRINGS:");
b.println();
List<ReferencedObjCluster.DupStrings> rsReverseChains = ds.dupStringClusters.get(0);
for (ReferencedObjCluster c : rsReverseChains) {
// For individual clusters, we set a smaller overhead threshold
if (c.getTotalOverhead() < ds.minOvhdToReport / 4) {
break;
}
b.println(c.clusterAsString(b.getMemNumFormatter()));
b.print(" ");
b.println(ReferenceChain.toStringInReverseOrder(c.getReferer(), printedRefChainDepth,
refChainStopperClassPrefixes));
}
b.println(DASH_SEPARATOR);
b.startSection("13. DUPLICATE PRIMITIVE ARRAY STATS:", "High overhead due to duplicate primitive arrays", 5.0);
DupArrayStats das = hs.dupArrayStats;
b.format("\nTotal primitive arrays: %,d Unique arrays: %,d Duplicate values: %,d Overhead: %s\n", das.nArrays,
das.nUniqueArrays, das.nDifferentDupArrayValues, b.k(das.dupArraysOverhead));
b.criticalCheck(das.dupArraysOverhead, "");
b.format("Top duplicate primitive arrays:\n");
b.format(" Ovhd Num objs Array len Value\n");
for (DupArrayStats.Entry entry : das.dupArrays) {
if (entry.overhead < ds.minOvhdToReport) {
break;
}
b.format("%14s %6d %6d ", b.k(entry.overhead), entry.nArrayInstances,
entry.firstArray.getLength());
String arrayAsString = entry.firstArray.valueAsString();
b.println(arrayAsString);
}
b.println(DASH_SEPARATOR);
b.startSection("14. NUMBER, OVERHEAD AND NEAREST FIELDS FOR DUPLICATE PRIMITIVE ARRAYS:");
b.println();
List<ReferencedObjCluster.DupArrays> daFields = ds.dupArrayClusters.get(1);
for (ReferencedObjCluster c : daFields) {
if (c.getTotalOverhead() < ds.minOvhdToReport / 4) {
break;
}
RefChainElement classAndField = c.getReferer();
String classAndFieldStr = ReferenceChain.toStringInStraightOrder(classAndField);
String fieldDefiningClass = getFieldDefiningClassFromFieldRefChain(
ReferenceChain.getRootElement(classAndField));
if (fieldDefiningClass != null) {
classAndFieldStr += " (defined in " + fieldDefiningClass + ")";
}
b.print(" ");
b.print(classAndFieldStr);
b.println(" -->");
b.println(c.clusterAsString(b.getMemNumFormatter()));
}
b.println(DASH_SEPARATOR);
b.startSection("15. NUMBER, OVERHEAD AND REF CHAINS FOR DUPLICATE PRIMITIVE ARRAYS:");
b.println();
List<ReferencedObjCluster.DupArrays> daReverseChains = ds.dupArrayClusters.get(0);
for (ReferencedObjCluster c : daReverseChains) {
// For individual clusters, we set a smaller overhead threshold
if (c.getTotalOverhead() < ds.minOvhdToReport / 4) {
break;
}
b.println(c.clusterAsString(b.getMemNumFormatter()));
b.print(" ");
b.println(ReferenceChain.toStringInReverseOrder(c.getReferer(), printedRefChainDepth,
refChainStopperClassPrefixes));
}
b.println(DASH_SEPARATOR);
b.startSection(
"16. WEAK HASHMAPS WITH REFS FROM VALUES TO KEYS\n"
+ " (conservative estimate; deep object size not calculated):",
"Found WeakHashMaps with references from values to keys, minimum overhead", 0.01);
b.format("\n Ovhd Num collections Type\n");
Constants.ProblemKind weakKind = Constants.ProblemKind.WEAK_MAP_WITH_BACK_REFS;
for (CollectionClassDescriptor cd : hs.overheadsByClass) {
int numProblematicCollections = cd.getNumProblematicCollections(weakKind);
if (numProblematicCollections == 0) {
continue;
}
String className = cd.getClazz().getHumanFriendlyName();
int ovhd = cd.getProblematicCollectionsOverhead(weakKind);
b.criticalCheck(ovhd, "");
b.format("%14s %,8d %s\n", b.k(ovhd), numProblematicCollections, className);
}
b.println();
List<ReferencedObjCluster.WeakHashMaps> wmReverseChains = ds.weakHashMapClusters.get(0);
for (ReferencedObjCluster c : wmReverseChains) {
// Here we print data for any overhead, just in case
b.println(c.clusterAsString(b.getMemNumFormatter()));
b.print(" ");
b.println(ReferenceChain.toStringInReverseOrder(c.getReferer(), printedRefChainDepth,
refChainStopperClassPrefixes));
}
b.println();
List<ReferencedObjCluster.WeakHashMaps> wmFields = ds.weakHashMapClusters.get(1);
for (ReferencedObjCluster c : wmFields) {
// Here we print data for any overhead, just in case
b.print(" ");
b.print(ReferenceChain.toStringInStraightOrder(c.getReferer()));
b.println(" -->");
b.println(c.clusterAsString(b.getMemNumFormatter()));
}
b.println();
b.println(DASH_SEPARATOR);
b.startSection("17. DATA FIELDS ALWAYS OR ALMOST ALWAYS NULL/ZERO, OR NO FIELDS:",
"High overhead due to fields that are null/zero/non-existent in", 1.0);
printProblemFieldsHistogram(hs.objHisto, true, 1.0f, ds.minOvhdToReport);
printProblemFieldsHistogram(hs.objHisto, true, 0.9f, ds.minOvhdToReport);
b.println(DASH_SEPARATOR);
b.startSection("18. PRIMITIVE DATA FIELDS WITH UNUSED HIGH BYTES:",
"High overhead due to primitive fields with unused high bytes", 1.0);
printProblemFieldsHistogram(hs.objHisto, false, 1.0f, ds.minOvhdToReport);
printProblemFieldsHistogram(hs.objHisto, false, 0.9f, ds.minOvhdToReport);
b.println(DASH_SEPARATOR);
b.startSection("19. STRING LENGTH STATISTICS:", "High memory consumption by Strings of length", 10.0);
List<LengthHistogram.Entry> strLenHisto = hs.stringLengthHistogram
.getPrunedAndSortedEntries(ds.minOvhdToReport);
b.println("\n Length Count Size");
b.println("----------------------------------------------");
for (LengthHistogram.Entry entry : strLenHisto) {
int strLen = entry.getLength();
String formattedLen = strLen >= 0 ? String.format("%,d", strLen) : "other";
b.format(" %9s %,10d %16s\n", formattedLen, entry.getCount(), b.k(entry.getSize()));
b.criticalCheck(entry.getSize(), formattedLen);
}
}