From c49248f7d55671637a3fb7d376aa1ae94f9551b4 Mon Sep 17 00:00:00 2001 From: "jaipilot[bot]" <273169020+jaipilot[bot]@users.noreply.github.com> Date: Sat, 22 Aug 2026 21:54:51 +0000 Subject: [PATCH] Avoid ArrayList boxing when collecting ParNew promotion-failure sizes --- .../parser/GenerationalHeapParser.java | 12 ++-- ...lHeapParserPromotionFailedDetailsTest.java | 56 +++++++++++++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 parser/src/test/java/com/microsoft/gctoolkit/parser/GenerationalHeapParserPromotionFailedDetailsTest.java diff --git a/parser/src/main/java/com/microsoft/gctoolkit/parser/GenerationalHeapParser.java b/parser/src/main/java/com/microsoft/gctoolkit/parser/GenerationalHeapParser.java index 28661fb02..1cd0e53ab 100644 --- a/parser/src/main/java/com/microsoft/gctoolkit/parser/GenerationalHeapParser.java +++ b/parser/src/main/java/com/microsoft/gctoolkit/parser/GenerationalHeapParser.java @@ -39,6 +39,7 @@ import java.util.AbstractMap; import java.util.ArrayList; +import java.util.Arrays; import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; @@ -622,16 +623,17 @@ public void parNewPromotionFailedDetails(GCLogTrace trace, String line) { scavengeTimeStamp = getClock(); garbageCollectionTypeForwardReference = GarbageCollectionTypes.ParNewPromotionFailed; gcCauseForwardReference = GCCause.PROMOTION_FAILED; - ArrayList blocks = new ArrayList<>(); + int[] blocks = new int[4]; + int blockCount = 0; GCLogTrace block = PARNEW_PROMOTION_FAILURE_SIZE_BLOCK.parse(line); if (block != null) { do { - blocks.add(block.getIntegerGroup(1)); + if (blockCount == blocks.length) + blocks = Arrays.copyOf(blocks, blocks.length * 2); + blocks[blockCount++] = block.getIntegerGroup(1); } while (block.hasNext()); } - promotionFailureSizesForwardReference = new int[blocks.size()]; - for (int index = 0; index < blocks.size(); index++) - promotionFailureSizesForwardReference[index] = blocks.get(index); + promotionFailureSizesForwardReference = Arrays.copyOf(blocks, blockCount); GCLogTrace memorySummary = BEFORE_AFTER_CONFIGURED_PAUSE_RULE.parse(line); youngMemoryPoolSummaryForwardReference = memorySummary.getOccupancyBeforeAfterWithMemoryPoolSizeSummary(1); scavengeDurationForwardReference = memorySummary.getDuration(); diff --git a/parser/src/test/java/com/microsoft/gctoolkit/parser/GenerationalHeapParserPromotionFailedDetailsTest.java b/parser/src/test/java/com/microsoft/gctoolkit/parser/GenerationalHeapParserPromotionFailedDetailsTest.java new file mode 100644 index 000000000..03e16564c --- /dev/null +++ b/parser/src/test/java/com/microsoft/gctoolkit/parser/GenerationalHeapParserPromotionFailedDetailsTest.java @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +package com.microsoft.gctoolkit.parser; + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +/** + * Locks the behavior of GenerationalHeapParser#parNewPromotionFailedDetails, which collects the + * per-thread promotion failure sizes found on a "ParNew (N: promotion failure size = X) ..." line. + * These characterizations pin the exact values, order, and count produced for zero, one, and many + * promotion failure size blocks so that the underlying collection strategy can be safely changed. + */ +public class GenerationalHeapParserPromotionFailedDetailsTest { + + private int[] promotionFailureSizesOf(GenerationalHeapParser parser) throws ReflectiveOperationException { + Field field = GenerationalHeapParser.class.getDeclaredField("promotionFailureSizesForwardReference"); + field.setAccessible(true); + return (int[]) field.get(parser); + } + + @Test + public void singlePromotionFailureSizeIsCaptured() throws ReflectiveOperationException { + GenerationalHeapParser parser = new GenerationalHeapParser(); + String line = "2015-05-26T12:23:33.483-0700: 4.484: [ParNew (0: promotion failure size = 8) (promotion failed): 19136K->19136K(19136K), 0.0300000 secs]"; + + parser.parNewPromotionFailedDetails(null, line); + + assertArrayEquals(new int[]{8}, promotionFailureSizesOf(parser)); + } + + @Test + public void multiplePromotionFailureSizesArePreservedInOrder() throws ReflectiveOperationException { + GenerationalHeapParser parser = new GenerationalHeapParser(); + String line = "2017-04-16T12:35:12.797-0700: 142237.056: [ParNew (0: promotion failure size = 3) (1: promotion failure size = 3) (2: promotion failure size = 3) (3: promotion failure size = 3) (4: promotion failure size = 3) (5: promotion failure size = 3) (6: promotion failure size = 3) (7: promotion failure size = 131074) (8: promotion failure size = 3) (9: promotion failure size = 3) (10: promotion failure size = 3) (11: promotion failure size = 3) (12: promotion failure size = 3) (13: promotion failure size = 3) (14: promotion failure size = 3) (15: promotion failure size = 3) (16: promotion failure size = 3) (17: promotion failure size = 3) (18: promotion failure size = 3) (19: promotion failure size = 3) (20: promotion failure size = 3) (21: promotion failure size = 3) (22: promotion failure size = 3) (23: promotion failure size = 3) (24: promotion failure size = 3) (25: promotion failure size = 4) (26: promotion failure size = 3) (27: promotion failure size = 3) (promotion failed): 1611303K->1607853K(1800000K), 0.4413433 secs]"; + + parser.parNewPromotionFailedDetails(null, line); + + int[] expected = {3, 3, 3, 3, 3, 3, 3, 131074, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3}; + assertArrayEquals(expected, promotionFailureSizesOf(parser)); + } + + @Test + public void noPromotionFailureSizeBlockYieldsEmptyArrayInsteadOfThrowing() throws ReflectiveOperationException { + GenerationalHeapParser parser = new GenerationalHeapParser(); + String line = "2014-10-24T06:04:47.413-0400: 748196.080: [ParNew (promotion failed): 19136K->19136K(19136K), 0.0300000 secs]"; + + assertDoesNotThrow(() -> parser.parNewPromotionFailedDetails(null, line)); + + assertArrayEquals(new int[0], promotionFailureSizesOf(parser)); + } +}