Skip to content

Commit

Permalink
Bug 582305 Improve Leak Suspects report for references in paths
Browse files Browse the repository at this point in the history
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=582305
Change-Id: Id969904bdc1e0aa6e2576cea19c1679f6ab5dd0e
  • Loading branch information
ajohnson1 committed Aug 21, 2023
1 parent bc010ce commit 30a656c
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 103 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2021 SAP AG and IBM Corporation.
* Copyright (c) 2008, 2023 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand All @@ -16,8 +16,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
Expand All @@ -29,6 +30,7 @@
import org.eclipse.mat.collect.BitField;
import org.eclipse.mat.internal.MATPlugin;
import org.eclipse.mat.internal.Messages;
import org.eclipse.mat.internal.snapshot.inspections.Path2GCRootsQuery;
import org.eclipse.mat.query.Bytes;
import org.eclipse.mat.query.Column;
import org.eclipse.mat.query.ContextProvider;
Expand Down Expand Up @@ -70,10 +72,6 @@ public class FindLeaksQuery implements IQuery
//
// ///////////////////////////////////////////

private final static Set<String> REFERENCE_FIELD_SET = new HashSet<String>(Arrays
.asList(new String[] { "referent" })); //$NON-NLS-1$
private final static Set<String> UNFINALIZED_REFERENCE_FIELD_SET = new HashSet<String>(Arrays
.asList(new String[] { "<" + GCRootInfo.getTypeAsString(GCRootInfo.Type.UNFINALIZED) + ">" })); //$NON-NLS-1$ //$NON-NLS-2$
private final static int MAX_DEPTH = 1000;

// ////////////////////////////////////////////
Expand All @@ -94,6 +92,11 @@ public class FindLeaksQuery implements IQuery
// @Argument(isMandatory = false, flag = "big_drop_ratio")
public double big_drop_ratio = 0.7;

public double group_suspects_accumulation_ratio = 0.8;

public List<String> excludes = Arrays.asList( //
new String[] { "java.lang.ref.Reference:referent", "java.lang.ref.Finalizer:unfinalized", "java.lang.Runtime:" + "<" + GCRootInfo.getTypeAsString(GCRootInfo.Type.UNFINALIZED) + ">" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$

public IResult execute(IProgressListener listener) throws Exception
{
long totalHeap;
Expand Down Expand Up @@ -227,6 +230,15 @@ private AccumulationPoint findAccumulationPoint(int bigObjectId) throws Snapshot
return null;
}

static class ExcludesConverter extends Path2GCRootsQuery
{
public static Map<IClass, Set<String>> convert(ISnapshot snapshot, List<String> excludes)
throws SnapshotException
{
return Path2GCRootsQuery.convert(snapshot, excludes);
}
}

private SuspectRecord buildSuspectRecordGroupOfObjects(ClassHistogramRecord record, IProgressListener listener)
throws SnapshotException
{
Expand All @@ -235,20 +247,9 @@ private SuspectRecord buildSuspectRecordGroupOfObjects(ClassHistogramRecord reco

// calculate the shortest paths to all
// avoid weak paths
Map<IClass, Set<String>> excludeMap = new HashMap<IClass, Set<String>>();
Collection<IClass> classes = snapshot.getClassesByName("java.lang.ref.WeakReference", true); //$NON-NLS-1$
if (classes != null)
for (IClass clazz : classes)
{
excludeMap.put(clazz, REFERENCE_FIELD_SET);
}
// Unfinalized objects from J9
classes = snapshot.getClassesByName("java.lang.Runtime", false); //$NON-NLS-1$
if (classes != null)
for (IClass clazz : classes)
{
excludeMap.put(clazz, UNFINALIZED_REFERENCE_FIELD_SET);
}
// Unfinalized objects from J9 and HotSpot
// convert excludes into the required format
Map<IClass, Set<String>> excludeMap = ExcludesConverter.convert(snapshot, excludes);

IMultiplePathsFromGCRootsComputer comp = snapshot.getMultiplePathsFromGCRoots(objectIds, excludeMap);

Expand All @@ -257,7 +258,16 @@ private SuspectRecord buildSuspectRecordGroupOfObjects(ClassHistogramRecord reco

if (listener.isCanceled())
throw new IProgressListener.OperationCanceledException();


if (records.length == 0)
{
// We have no paths with all the excludes, so try again without the excludes
comp = snapshot.getMultiplePathsFromGCRoots(objectIds, Collections.emptyMap());
records = comp.getPathsByGCRoot(listener);
if (listener.isCanceled())
throw new IProgressListener.OperationCanceledException();
}

if (records.length > 0)
{
int numPaths = comp.getAllPaths(listener).length;
Expand All @@ -273,7 +283,7 @@ private SuspectRecord buildSuspectRecordGroupOfObjects(ClassHistogramRecord reco
MultiplePathsFromGCRootsRecord parentRecord = records[0];

// parentRecord.getReferencedRetainedSize()
int threshold = (int) (0.8 * objectIds.length);
int threshold = (int) (group_suspects_accumulation_ratio * objectIds.length);

while (parentRecord.getCount() > threshold)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
Expand All @@ -32,6 +30,7 @@
import org.eclipse.mat.collect.ArrayIntBig;
import org.eclipse.mat.collect.BitField;
import org.eclipse.mat.collect.HashMapIntObject;
import org.eclipse.mat.inspections.FindLeaksQuery.ExcludesConverter;
import org.eclipse.mat.inspections.FindLeaksQuery.SuspectRecord;
import org.eclipse.mat.internal.MATPlugin;
import org.eclipse.mat.internal.Messages;
Expand Down Expand Up @@ -79,10 +78,6 @@ public class FindLeaksQuery2 implements IQuery
//
// ///////////////////////////////////////////

private final static Set<String> REFERENCE_FIELD_SET = new HashSet<String>(Arrays
.asList(new String[] { "referent" })); //$NON-NLS-1$
private final static Set<String> UNFINALIZED_REFERENCE_FIELD_SET = new HashSet<String>(Arrays
.asList(new String[] { "<" + GCRootInfo.getTypeAsString(GCRootInfo.Type.UNFINALIZED) + ">" })); //$NON-NLS-1$ //$NON-NLS-2$
private final static int MAX_DEPTH = 1000;

// ////////////////////////////////////////////
Expand Down Expand Up @@ -113,7 +108,7 @@ public class FindLeaksQuery2 implements IQuery
public Pattern mask = Pattern.compile("\\s@ 0x[0-9a-f]+"//$NON-NLS-1$
+ "|^(\\[[0-9]+\\], ){0,100}\\[[0-9]+\\](,\\.\\.\\.)?$"//$NON-NLS-1$
+ "|(?<=\\p{javaJavaIdentifierPart}\\[)\\d+(?=\\])"//$NON-NLS-1$
);
);

@Argument(isMandatory = false, flag = "x")
public String[] extraReferences = new String[] {
Expand All @@ -126,6 +121,11 @@ public class FindLeaksQuery2 implements IQuery
@Argument(isMandatory = false, flag = "xfile")
public File extraReferencesListFile;

public double group_suspects_accumulation_ratio = 0.8;

public List<String> excludes = Arrays.asList( //
new String[] { "java.lang.ref.Reference:referent", "java.lang.ref.Finalizer:unfinalized", "java.lang.Runtime:" + "<" + GCRootInfo.getTypeAsString(GCRootInfo.Type.UNFINALIZED) + ">" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$

static final int retainedDiffCol = 5;
static final int simpleDiffCol = 2;

Expand Down Expand Up @@ -177,7 +177,7 @@ public IResult execute(IProgressListener listener) throws Exception
ArrayInt suspiciousObjects = new ArrayInt();
int i = 0;
HashMapIntObject<ClassRecord>map = new HashMapIntObject<ClassRecord>();
final HashMapIntObject<Object>rowmap = new HashMapIntObject<Object>();
final HashMapIntObject<Object>rowmap = new HashMapIntObject<Object>();
while (i < topDominators.size())
{
Object row = topDominators.get(i);
Expand Down Expand Up @@ -342,7 +342,7 @@ private long readCol(IResultTree compTree, final Object row, final int retainedD
deltaRetained = ((Bytes)colv).getValue();
else if (colv instanceof Number)
deltaRetained = ((Number)colv).longValue();
else
else
deltaRetained = 0;
return deltaRetained;
}
Expand Down Expand Up @@ -396,10 +396,10 @@ private FindLeaksQuery.AccumulationPoint findAccumulationPoint(int bigObjectId,
int depth = 0;
while (tree.hasChildren(row) && (rows = tree.getChildren(row)) != null && rows.size() != 0 && depth < MAX_DEPTH)
{
long dominatedRetainedSize = this.readCol(tree, rows.get(0), retainedDiffCol);
long dominatedRetainedSize = this.readCol(tree, rows.get(0), retainedDiffCol);
if ((double)dominatedRetainedSize / dominatorRetainedSize < big_drop_ratio)
{
return new AccumulationPoint(snapshot.getObject(dominator), dominatorRetainedSize, path.toArray());
return new AccumulationPoint(snapshot.getObject(dominator), dominatorRetainedSize, path.toArray());
}

dominatorRetainedSize = dominatedRetainedSize;
Expand All @@ -425,20 +425,9 @@ private FindLeaksQuery.SuspectRecord buildSuspectRecordGroupOfObjects(ClassHisto

// calculate the shortest paths to all
// avoid weak paths
Map<IClass, Set<String>> excludeMap = new HashMap<IClass, Set<String>>();
Collection<IClass> classes = snapshot.getClassesByName("java.lang.ref.WeakReference", true); //$NON-NLS-1$
if (classes != null)
for (IClass clazz : classes)
{
excludeMap.put(clazz, REFERENCE_FIELD_SET);
}
// Unfinalized objects from J9
classes = snapshot.getClassesByName("java.lang.Runtime", false); //$NON-NLS-1$
if (classes != null)
for (IClass clazz : classes)
{
excludeMap.put(clazz, UNFINALIZED_REFERENCE_FIELD_SET);
}
// Unfinalized objects from J9 and HotSpot
// convert excludes into the required format
Map<IClass, Set<String>> excludeMap = ExcludesConverter.convert(snapshot, excludes);

IMultiplePathsFromGCRootsComputer comp = snapshot.getMultiplePathsFromGCRoots(objectIds, excludeMap);

Expand All @@ -447,7 +436,16 @@ private FindLeaksQuery.SuspectRecord buildSuspectRecordGroupOfObjects(ClassHisto

if (listener.isCanceled())
throw new IProgressListener.OperationCanceledException();


if (records.length == 0)
{
// We have no paths with all the excludes, so try again without the excludes
comp = snapshot.getMultiplePathsFromGCRoots(objectIds, Collections.emptyMap());
records = comp.getPathsByGCRoot(listener);
if (listener.isCanceled())
throw new IProgressListener.OperationCanceledException();
}

if (records.length > 0)
{
int numPaths = comp.getAllPaths(listener).length;
Expand All @@ -463,7 +461,7 @@ private FindLeaksQuery.SuspectRecord buildSuspectRecordGroupOfObjects(ClassHisto
MultiplePathsFromGCRootsRecord parentRecord = records[0];

// parentRecord.getReferencedRetainedSize()
int threshold = (int) (0.8 * objectIds.length);
int threshold = (int) (group_suspects_accumulation_ratio * objectIds.length);

Object row = null;
while (parentRecord.getCount() > threshold)
Expand Down

0 comments on commit 30a656c

Please sign in to comment.