82 * Defines the relative amount of live set increase per second that corresponds to a rule score 83 * of 75. 84 */ 85 private static final double PERCENT_OF_HEAP_INCREASE_PER_SECOND = 0.01; 86 87 private static final String RESULT_ID = "IncreasingLiveSet"; //$NON-NLS-1$ 88 89 public static final TypedPreference<IQuantity> CLASSES_LOADED_PERCENT = new TypedPreference<>( 90 "memleak.classload.percent", Messages.getString(Messages.IncreasingLiveSetRule_LOADED_CLASSES_PERCENT), //$NON-NLS-1$ 91 Messages.getString(Messages.IncreasingLiveSetRule_LOADED_CLASSES_PERCENT_DESC), PERCENTAGE, 92 PERCENT.quantity(90)); 93 public static final TypedPreference<IQuantity> RELEVANCE_THRESHOLD = new TypedPreference<>( 94 "memleak.reference.tree.depth", Messages.getString(Messages.IncreasingLiveSetRule_RELEVANCE_THRESHOLD), //$NON-NLS-1$ 95 Messages.getString(Messages.IncreasingLiveSetRule_RELEVANCE_THRESHOLD_DESC), NUMBER, 96 NUMBER_UNITY.quantity(0.5d)); 97 private static final List<TypedPreference<?>> CONFIG_ATTRIBUTES = Arrays 98 .<TypedPreference<?>> asList(CLASSES_LOADED_PERCENT, RELEVANCE_THRESHOLD); 99 100 private Result getResult(IItemCollection items, IPreferenceValueProvider valueProvider) { 101 EventAvailability eventAvailability = RulesToolkit.getEventAvailability(items, JdkTypeIDs.HEAP_SUMMARY); 102 if (eventAvailability == EventAvailability.UNAVAILABLE || eventAvailability == EventAvailability.DISABLED) { 103 return RulesToolkit.getEventAvailabilityResult(this, items, eventAvailability, JdkTypeIDs.HEAP_SUMMARY); 104 } 105 106 IQuantity postWarmupTime = getPostWarmupTime(items, valueProvider.getPreferenceValue(CLASSES_LOADED_PERCENT)); 107 Iterator<? extends IItemIterable> allAfterItems = items.apply(JdkFilters.HEAP_SUMMARY_AFTER_GC).iterator(); 108 double score = 0; 109 IQuantity liveSetIncreasePerSecond = UnitLookup.MEMORY.getUnit(BinaryPrefix.MEBI).quantity(0); 110 if (allAfterItems.hasNext()) { 111 // FIXME: Handle multiple IItemIterable 112 IItemIterable afterItems = allAfterItems.next(); 113 IMemberAccessor<IQuantity, IItem> timeAccessor = JfrAttributes.END_TIME.getAccessor(afterItems.getType()); 114 IMemberAccessor<IQuantity, IItem> memAccessor = JdkAttributes.HEAP_USED.getAccessor(afterItems.getType()); 115 116 liveSetIncreasePerSecond = UnitLookup.MEMORY.getUnit(BinaryPrefix.MEBI) 117 .quantity(RulesToolkit.leastSquareMemory(afterItems.iterator(), timeAccessor, memAccessor)); 118 119 if (postWarmupTime == null) { 120 return RulesToolkit.getTooFewEventsResult(this); 121 } 122 IQuantity postWarmupHeapSize = items 123 .apply(ItemFilters.and(JdkFilters.HEAP_SUMMARY_AFTER_GC, 124 ItemFilters.moreOrEqual(JfrAttributes.START_TIME, postWarmupTime))) 125 .getAggregate(JdkAggregators.first(JdkAttributes.HEAP_USED)); 126 if (postWarmupHeapSize == null) { 127 return RulesToolkit.getTooFewEventsResult(this); 128 } 129 double relativeIncreasePerSecond = liveSetIncreasePerSecond.ratioTo(postWarmupHeapSize); 130 score = RulesToolkit.mapExp100(relativeIncreasePerSecond, PERCENT_OF_HEAP_INCREASE_PER_SECOND); 131 } 132 // If we have Old Object Sample events we can attempt to find suitable memory leak class candidates 133 // otherwise we just return the basic increasing live set score 134 EventAvailability ea = RulesToolkit.getEventAvailability(items, JdkTypeIDs.OLD_OBJECT_SAMPLE); 135 // FIXME: Should construct an message using memoryIncrease, not use a hard limit 136 if (score >= 25 && (ea == EventAvailability.DISABLED || ea == EventAvailability.UNAVAILABLE)) { 137 String shortMessage = MessageFormat.format( 138 Messages.getString(Messages.IncreasingLiveSetRuleFactory_TEXT_INFO), 139 liveSetIncreasePerSecond.displayUsing(IDisplayable.AUTO)); 140 String longMessage = shortMessage + "<p>" //$NON-NLS-1$ 141 + Messages.getString(Messages.IncreasingLiveSetRuleFactory_TEXT_INFO_LONG); 142 return new Result(this, score, shortMessage, longMessage, JdkQueries.HEAP_SUMMARY_AFTER_GC); 143 } else if (score < 25) { 144 return new Result(this, score, Messages.getString(Messages.IncreasingLiveSetRule_TEXT_OK)); 145 } 146 147 // step 1. extract events from after the estimated warmup period 148 IItemCollection oldObjectItems = items.apply(ItemFilters.and(ItemFilters.type(JdkTypeIDs.OLD_OBJECT_SAMPLE), 149 ItemFilters.more(JfrAttributes.START_TIME, postWarmupTime))); 150 151 ReferenceTreeModel tree = ReferenceTreeModel.buildReferenceTree(oldObjectItems); 152 153 // step 2. perform a balance calculation on the old object sample events aggregated by class count 154 boolean anyReferrerChains = false; 155 for (ReferenceTreeObject referenceTreeObject : tree.getLeakObjects()) { 156 if (referenceTreeObject.getParent() != null) { | 82 * Defines the relative amount of live set increase per second that corresponds to a rule score 83 * of 75. 84 */ 85 private static final double PERCENT_OF_HEAP_INCREASE_PER_SECOND = 0.01; 86 87 private static final String RESULT_ID = "IncreasingLiveSet"; //$NON-NLS-1$ 88 89 public static final TypedPreference<IQuantity> CLASSES_LOADED_PERCENT = new TypedPreference<>( 90 "memleak.classload.percent", Messages.getString(Messages.IncreasingLiveSetRule_LOADED_CLASSES_PERCENT), //$NON-NLS-1$ 91 Messages.getString(Messages.IncreasingLiveSetRule_LOADED_CLASSES_PERCENT_DESC), PERCENTAGE, 92 PERCENT.quantity(90)); 93 public static final TypedPreference<IQuantity> RELEVANCE_THRESHOLD = new TypedPreference<>( 94 "memleak.reference.tree.depth", Messages.getString(Messages.IncreasingLiveSetRule_RELEVANCE_THRESHOLD), //$NON-NLS-1$ 95 Messages.getString(Messages.IncreasingLiveSetRule_RELEVANCE_THRESHOLD_DESC), NUMBER, 96 NUMBER_UNITY.quantity(0.5d)); 97 private static final List<TypedPreference<?>> CONFIG_ATTRIBUTES = Arrays 98 .<TypedPreference<?>> asList(CLASSES_LOADED_PERCENT, RELEVANCE_THRESHOLD); 99 100 private Result getResult(IItemCollection items, IPreferenceValueProvider valueProvider) { 101 EventAvailability eventAvailability = RulesToolkit.getEventAvailability(items, JdkTypeIDs.HEAP_SUMMARY); 102 if (eventAvailability == EventAvailability.UNKNOWN || eventAvailability == EventAvailability.DISABLED) { 103 return RulesToolkit.getEventAvailabilityResult(this, items, eventAvailability, JdkTypeIDs.HEAP_SUMMARY); 104 } 105 106 IQuantity postWarmupTime = getPostWarmupTime(items, valueProvider.getPreferenceValue(CLASSES_LOADED_PERCENT)); 107 Iterator<? extends IItemIterable> allAfterItems = items.apply(JdkFilters.HEAP_SUMMARY_AFTER_GC).iterator(); 108 double score = 0; 109 IQuantity liveSetIncreasePerSecond = UnitLookup.MEMORY.getUnit(BinaryPrefix.MEBI).quantity(0); 110 if (allAfterItems.hasNext()) { 111 // FIXME: Handle multiple IItemIterable 112 IItemIterable afterItems = allAfterItems.next(); 113 IMemberAccessor<IQuantity, IItem> timeAccessor = JfrAttributes.END_TIME.getAccessor(afterItems.getType()); 114 IMemberAccessor<IQuantity, IItem> memAccessor = JdkAttributes.HEAP_USED.getAccessor(afterItems.getType()); 115 116 liveSetIncreasePerSecond = UnitLookup.MEMORY.getUnit(BinaryPrefix.MEBI) 117 .quantity(RulesToolkit.leastSquareMemory(afterItems.iterator(), timeAccessor, memAccessor)); 118 119 if (postWarmupTime == null) { 120 return RulesToolkit.getTooFewEventsResult(this); 121 } 122 IQuantity postWarmupHeapSize = items 123 .apply(ItemFilters.and(JdkFilters.HEAP_SUMMARY_AFTER_GC, 124 ItemFilters.moreOrEqual(JfrAttributes.START_TIME, postWarmupTime))) 125 .getAggregate(JdkAggregators.first(JdkAttributes.HEAP_USED)); 126 if (postWarmupHeapSize == null) { 127 return RulesToolkit.getTooFewEventsResult(this); 128 } 129 double relativeIncreasePerSecond = liveSetIncreasePerSecond.ratioTo(postWarmupHeapSize); 130 score = RulesToolkit.mapExp100(relativeIncreasePerSecond, PERCENT_OF_HEAP_INCREASE_PER_SECOND); 131 } 132 // If we have Old Object Sample events we can attempt to find suitable memory leak class candidates 133 // otherwise we just return the basic increasing live set score 134 EventAvailability ea = RulesToolkit.getEventAvailability(items, JdkTypeIDs.OLD_OBJECT_SAMPLE); 135 // FIXME: Should construct an message using memoryIncrease, not use a hard limit 136 if (score >= 25 && (ea == EventAvailability.DISABLED || ea == EventAvailability.UNKNOWN)) { 137 String shortMessage = MessageFormat.format( 138 Messages.getString(Messages.IncreasingLiveSetRuleFactory_TEXT_INFO), 139 liveSetIncreasePerSecond.displayUsing(IDisplayable.AUTO)); 140 String longMessage = shortMessage + "<p>" //$NON-NLS-1$ 141 + Messages.getString(Messages.IncreasingLiveSetRuleFactory_TEXT_INFO_LONG); 142 return new Result(this, score, shortMessage, longMessage, JdkQueries.HEAP_SUMMARY_AFTER_GC); 143 } else if (score < 25) { 144 return new Result(this, score, Messages.getString(Messages.IncreasingLiveSetRule_TEXT_OK)); 145 } 146 147 // step 1. extract events from after the estimated warmup period 148 IItemCollection oldObjectItems = items.apply(ItemFilters.and(ItemFilters.type(JdkTypeIDs.OLD_OBJECT_SAMPLE), 149 ItemFilters.more(JfrAttributes.START_TIME, postWarmupTime))); 150 151 ReferenceTreeModel tree = ReferenceTreeModel.buildReferenceTree(oldObjectItems); 152 153 // step 2. perform a balance calculation on the old object sample events aggregated by class count 154 boolean anyReferrerChains = false; 155 for (ReferenceTreeObject referenceTreeObject : tree.getLeakObjects()) { 156 if (referenceTreeObject.getParent() != null) { |