[515399] Use BitField not SetInt for ComponentReportQuery

retained list of objects could be huge, so use a BitField in that case
rather than SetInt to avoid memory and capacity problems

Change-Id: Ic11676bcad1508b2a0c63bcae7c3c3ff05d0fef3
diff --git a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/component/ComponentReportQuery.java b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/component/ComponentReportQuery.java
index 7b93ceb..da413d2 100644
--- a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/component/ComponentReportQuery.java
+++ b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/component/ComponentReportQuery.java
@@ -22,6 +22,7 @@
 

 import org.eclipse.mat.SnapshotException;

 import org.eclipse.mat.collect.ArrayInt;

+import org.eclipse.mat.collect.BitField;

 import org.eclipse.mat.collect.SetInt;

 import org.eclipse.mat.inspections.InspectionAssert;

 import org.eclipse.mat.inspections.ReferenceQuery;

@@ -845,10 +846,26 @@
             return;

         }

 

-        // SetInt will resize when it is 75% full, so allocate it big enough now

-        SetInt retainedSet = new SetInt(Math.max(((retained.length + 2) / 3) * 4, retained.length));

+        // Currently SetInt uses a lot of memory - 32+8 bits @ 75% capacity = 53 bits per item

+        boolean useBits = retained.length > Math.max(100000, snapshot.getSnapshotInfo().getNumberOfObjects() / 53);

+        SetInt retainedSet = null;

+        BitField retainedIds = null;

+        if (useBits)

+        {

+            retainedIds = new BitField(snapshot.getSnapshotInfo().getNumberOfObjects());

+        }

+        else

+        {

+            // SetInt will resize when it is 75% full, so allocate it big enough now

+            retainedSet = new SetInt(Math.max(((retained.length + 2) / 3) * 4, retained.length));

+        }

         for (int ii = 0; ii < retained.length; ii++)

-            retainedSet.add(retained[ii]);

+        {

+            if (useBits)

+                retainedIds.set(retained[ii]);

+            else

+                retainedSet.add(retained[ii]);

+        }

 

         // Avoid duplicates from the two approaches by using a set

         SetInt finalizers = new SetInt();

@@ -863,7 +880,7 @@
                 if (ref != null)

                 {

                     int referentId = ref.getObjectId();

-                    if (retainedSet.contains(referentId))

+                    if (useBits ? retainedIds.get(referentId) : retainedSet.contains(referentId))

                     {

                         finalizers.add(referentId);

                     }

@@ -881,7 +898,7 @@
                                 || rootInfo.getType() == GCRootInfo.Type.FINALIZABLE)

                 {

                     int referentId = rootInfo.getObjectId();

-                    if (retainedSet.contains(referentId))

+                    if (useBits ? retainedIds.get(referentId) : retainedSet.contains(referentId))

                     {

                         finalizers.add(referentId);

                     }