private void formatDetailedStats()

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);
		}
	}