Show unreachable objects in ahat.
But don't count them against heap size or instance counts.
Bug: 33828707
Test: ahat tests, including new InstanceTest.unreachableReferent.
Change-Id: Ic39b6d5569159497dcc76c342e22ed99d2a71307
diff --git a/tools/ahat/src/Summarizer.java b/tools/ahat/src/Summarizer.java
index 7f4dcbf..016eab4 100644
--- a/tools/ahat/src/Summarizer.java
+++ b/tools/ahat/src/Summarizer.java
@@ -50,6 +50,11 @@
formatted.append(DocString.removed("del "));
}
+ // Annotate unreachable objects as such.
+ if (!inst.isReachable()) {
+ formatted.append("unreachable ");
+ }
+
// Annotate roots as roots.
if (inst.isRoot()) {
formatted.append("root ");
diff --git a/tools/ahat/src/heapdump/AhatInstance.java b/tools/ahat/src/heapdump/AhatInstance.java
index 24956f2..e6b9c00 100644
--- a/tools/ahat/src/heapdump/AhatInstance.java
+++ b/tools/ahat/src/heapdump/AhatInstance.java
@@ -31,6 +31,7 @@
private long mSize;
private long mTotalRetainedSize;
private long mRetainedSizes[]; // Retained size indexed by heap index
+ private boolean mIsReachable;
private AhatHeap mHeap;
private AhatInstance mImmediateDominator;
private AhatInstance mNextInstanceToGcRoot;
@@ -64,6 +65,7 @@
mId = inst.getId();
mSize = inst.getSize();
mTotalRetainedSize = inst.getTotalRetainedSize();
+ mIsReachable = inst.isReachable();
List<AhatHeap> heaps = snapshot.getHeaps();
mRetainedSizes = new long[heaps.size()];
@@ -149,6 +151,13 @@
}
/**
+ * Returns whether this object is strongly-reachable.
+ */
+ public boolean isReachable() {
+ return mIsReachable;
+ }
+
+ /**
* Returns the heap that this instance is allocated on.
*/
public AhatHeap getHeap() {
diff --git a/tools/ahat/src/heapdump/AhatSnapshot.java b/tools/ahat/src/heapdump/AhatSnapshot.java
index 6b4953e..20b85da 100644
--- a/tools/ahat/src/heapdump/AhatSnapshot.java
+++ b/tools/ahat/src/heapdump/AhatSnapshot.java
@@ -106,17 +106,15 @@
TObjectProcedure<Instance> doCreate = new TObjectProcedure<Instance>() {
@Override
public boolean execute(Instance inst) {
- if (inst.isReachable()) {
- long id = inst.getId();
- if (inst instanceof ClassInstance) {
- mInstances.add(new AhatClassInstance(id));
- } else if (inst instanceof ArrayInstance) {
- mInstances.add(new AhatArrayInstance(id));
- } else if (inst instanceof ClassObj) {
- AhatClassObj classObj = new AhatClassObj(id);
- mInstances.add(classObj);
- mClasses.put(((ClassObj)inst).getClassName(), classObj);
- }
+ long id = inst.getId();
+ if (inst instanceof ClassInstance) {
+ mInstances.add(new AhatClassInstance(id));
+ } else if (inst instanceof ArrayInstance) {
+ mInstances.add(new AhatArrayInstance(id));
+ } else if (inst instanceof ClassObj) {
+ AhatClassObj classObj = new AhatClassObj(id);
+ mInstances.add(classObj);
+ mClasses.put(((ClassObj)inst).getClassName(), classObj);
}
return true;
}
@@ -146,7 +144,9 @@
mRooted.add(ahat);
}
- ahat.getHeap().addToSize(ahat.getSize());
+ if (inst.isReachable()) {
+ ahat.getHeap().addToSize(ahat.getSize());
+ }
// Update sites.
StackFrame[] frames = null;
diff --git a/tools/ahat/src/heapdump/Site.java b/tools/ahat/src/heapdump/Site.java
index a551901..738eaf0 100644
--- a/tools/ahat/src/heapdump/Site.java
+++ b/tools/ahat/src/heapdump/Site.java
@@ -129,19 +129,21 @@
while (true) {
site.mObjects.add(inst);
- AhatHeap heap = inst.getHeap();
- if (heap.getIndex() >= site.mSizesByHeap.length) {
- long[] newSizes = new long[heap.getIndex() + 1];
- for (int i = 0; i < site.mSizesByHeap.length; i++) {
- newSizes[i] = site.mSizesByHeap[i];
- }
- site.mSizesByHeap = newSizes;
- }
- site.mSizesByHeap[heap.getIndex()] += inst.getSize();
-
ObjectsInfo info = site.getObjectsInfo(inst.getHeap(), inst.getClassObj());
- info.numInstances++;
- info.numBytes += inst.getSize();
+ if (inst.isReachable()) {
+ AhatHeap heap = inst.getHeap();
+ if (heap.getIndex() >= site.mSizesByHeap.length) {
+ long[] newSizes = new long[heap.getIndex() + 1];
+ for (int i = 0; i < site.mSizesByHeap.length; i++) {
+ newSizes[i] = site.mSizesByHeap[i];
+ }
+ site.mSizesByHeap = newSizes;
+ }
+ site.mSizesByHeap[heap.getIndex()] += inst.getSize();
+
+ info.numInstances++;
+ info.numBytes += inst.getSize();
+ }
if (depth > 0) {
StackFrame next = frames[depth - 1];
diff --git a/tools/ahat/test-dump/Main.java b/tools/ahat/test-dump/Main.java
index 4a2234c..7a05b1c 100644
--- a/tools/ahat/test-dump/Main.java
+++ b/tools/ahat/test-dump/Main.java
@@ -18,6 +18,7 @@
import java.io.IOException;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
@@ -73,6 +74,7 @@
public PhantomReference aPhantomReference = new PhantomReference(anObject, referenceQueue);
public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue);
public WeakReference aNullReferentReference = new WeakReference(null, referenceQueue);
+ public SoftReference aSoftReference = new SoftReference(new Object());
public byte[] bigArray;
public ObjectTree[] gcPathArray = new ObjectTree[]{null, null,
new ObjectTree(
diff --git a/tools/ahat/test/InstanceTest.java b/tools/ahat/test/InstanceTest.java
index 7173b11..3a50150 100644
--- a/tools/ahat/test/InstanceTest.java
+++ b/tools/ahat/test/InstanceTest.java
@@ -223,6 +223,16 @@
}
@Test
+ public void unreachableReferent() throws IOException {
+ // The test dump program should never be under enough GC pressure for the
+ // soft reference to be cleared. Ensure that ahat will show the soft
+ // reference as having a non-null referent.
+ TestDump dump = TestDump.getTestDump();
+ AhatInstance ref = dump.getDumpedAhatInstance("aSoftReference");
+ assertNotNull(ref.getReferent());
+ }
+
+ @Test
public void gcRootPath() throws IOException {
TestDump dump = TestDump.getTestDump();
@@ -359,14 +369,6 @@
}
@Test
- public void reverseReferencesAreNotUnreachable() throws IOException {
- TestDump dump = TestDump.getTestDump();
- AhatInstance obj = dump.getDumpedAhatInstance("basicString");
- assertEquals(2, obj.getHardReverseReferences().size());
- assertEquals(0, obj.getSoftReverseReferences().size());
- }
-
- @Test
public void asStringEmbedded() throws IOException {
// Set up a heap dump with an instance of java.lang.String of
// "hello" with instance id 0x42 that is backed by a char array that is