0

I'm currently looking at the heap dump of this silly little test class (taken at the very end of the main method):

public class WeakRefTest {
    static final class RefObj1 { int i; }
    static final class RefObj2 { int j; }

    public static void main(String[] args) {
        Set<WeakReference<?>> objects = new HashSet<>();    
        RefObj1 obj1 = new RefObj1();
        RefObj2 obj2 = new RefObj2();
        for (int i = 0; i < 1000; i++) {
            objects.add(new WeakReference<RefObj1>(obj1));
            objects.add(new WeakReference<RefObj2>(obj2));
        }
    }
}

Now I'm trying to figure out how to count the number of references to a specific class in objects. If this were a SQL database, it'd be easy:

select objects.className as referent, count(*) as cnt
  from java.lang.ref.WeakReference ref 
    inner join heapObjects objects on ref.referent = objects.objectId
  group by objects.className;

Result:

referent | cnt
===================
WeakRefTest$RefObj1 | 1000
WeakRefTest$RefObj2 | 1000

After some research, I figured I can construct a Eclipse MAT OQL query that gives me the classes involved:

select DISTINCT OBJECTS classof(ref.referent) from java.lang.ref.WeakReference ref

Alas, this doesn't include their count and OQL doesn't seem to support a GROUP BY clause. Any ideas how to get this information?

Edited to add: In reality, none of the objects added to the Set (nor the Set implementation itself, obviously) are under my control. So sorry, modifying RefObj1 and RefObj2 isn't allowed.

Edit2: I found this related question about using OQL in jvisualvm but it turns out that OQL is actually Javascript unleashed at a heap dump. I'd be fine with something like that, too. But playing around with it hasn't produced results for me, yet. I'll update the question if that changes.

Community
  • 1
  • 1
mabi
  • 5,279
  • 2
  • 43
  • 78

3 Answers3

1
  1. Open the histogram view (there is a toolbar button for this, which looks like a bar graph).
  2. In the first row of the histogram view where it says "Regex", type WeakReference to filter the view.
  3. Find the java.lang.ref.WeakReference line, right-click, and choose "Show Objects By Class" -> "By Outgoing References".
  4. The resulting view should be summarize the objects being referred to, grouped by class as you require. The Objects column should indicate the number of instances for each class.
JimN
  • 3,120
  • 22
  • 35
  • I'll accept this one if you make it say "outgoing" (because `WeakReference.referent` seems to be "outgoing" in my version). – mabi Jun 10 '14 at 20:38
0

You could just write a method in the object that returns the information and call that from Eclipse...

Since you cannot modify the object then the next best thing will be to write a utility function in some method that you can modify and call that from the eclipse debugger. I don't know Eclipse well enough to help you do it without inserting something to the source code, sorry.

Tim B
  • 40,716
  • 16
  • 83
  • 128
  • Thanks for pointing this out, but sadly it's not that simple in my reality. I've updated the question to reflect this. – mabi Jun 10 '14 at 19:19
  • @mabi Updated my answer, but if that doesn't help you then you need an Eclipse expert :) – Tim B Jun 10 '14 at 19:26
  • Hmm, yeah, injecting code is difficult in my scenario (otherwise I wouldn't need a heap dump to begin with ;) – mabi Jun 10 '14 at 19:30
0

I would use a Weak HashSet. You can just use set.size() to get the number of references still alive.

static final class RefObj1 { int i; }
static final class RefObj2 { int j; }

public static void main(String[] args) {
    Set objects = Collections.newSetFroMap(new WeakHashMap());
    RefObj1 obj1 = new RefObj1();
    RefObj2 obj2 = new RefObj2();
    for (int i = 0; i < 1000; i++) {
        objects.add(obj1);
        objects.add(obj2);
    }
    obj1 = null;
    System.gc();
    System.out.println("Objects left is " + objects.size());
}

I would expect this to print 0, 1 or 2 depending on how the objects are cleaned up.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • I obviously suck at problem descriptions. I only have a heap dump generated at the end of `main` and want to reverse engineer the contents of `objects`. Getting the total size is easy (just by looking at the `HashMap` fields), but I'm stuck at diving into the contents of the `Set`. I've updated the question to (hopefully) make it clearer. – mabi Jun 10 '14 at 20:05