1

I am fighting with garbage collector in Java. I want to list all the objects that are reachable from a certain object in three lists, depending on the reference type: strong, soft, weak. No phantom there. I know I need to do it recursively and by reflection, but I can't find a simple way to achieve it. Could you please help me? It's not a very difficult problem, but I don't know how to achieve it in a simple and correct way. Note I am not trying to detect memory leaks.

   public static List < Object > getStronglyReachable (Object from)
     // contains all objects that are ONLY strongly reachable

   public static List < Object > getSoftlyReachable (Object from)
     // contains all objects that are strongly OR softly reachable

   public static List < Object > getWeaklyReachable (Object from)
     // contains all objects that are strongly OR softly OR weakly reachable

Here is what I have got currently, but it is not really working:

private static void collectAllReachableObjects (Object from, Set < Object > result) throws IllegalArgumentException, IllegalAccessException
{
    // if it's already added, don't do that again
    if (result.contains (from))
        return;

    // isStrongReference makes softAllowed false and weakAllowed false;
    // isSoftReference makes softAllowed true and weakAllowed false;
    // isWeakReference makes softAllowed true and weakAllowed true;
    // Phantom References are never allowed
    if (PhantomReference.class.isAssignableFrom (from.getClass ())) return;
    if (weakAllowed == false &&  WeakReference.class.isAssignableFrom (from.getClass ())) return;
    if (softAllowed == false &&  SoftReference.class.isAssignableFrom (from.getClass ())) return;

    // add to my list
    result.add (from);

    // if an object is an array, iterate over its elements
    if (from.getClass ().isArray ())
        for (int i = 0; i < Array.getLength (from); i++)
            collectAllReachableObjects (Array.get (from, i), result);

    Class < ? > c = from.getClass ();
    while (c != null)
    {
        Field fields[] = c.getDeclaredFields ();
        for (Field field : fields)
        {
            boolean wasAccessible = field.isAccessible ();
            field.setAccessible (true);
            Object value = field.get (from);
            if (value != null)
            {
                collectAllReachableObjects (value, result);
            }
            field.setAccessible (wasAccessible);
        }
        c = c.getSuperclass ();
    }
}
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
user3572544
  • 189
  • 7
  • 2
    Don't do this. Use [VisualVM](http://visualvm.java.net/) and the [OQL console](https://visualvm.java.net/oqlhelp.html). – Boris the Spider Apr 27 '14 at 10:02
  • Unfortunately I need it, I can't use those tools, as I'm not trying to detect memory leaks. I'm building something a bit more complicated, but to present it to users. This is just a necessary part of it. – user3572544 Apr 27 '14 at 10:07
  • 1
    *"This is just a necessary part of it."* - Then I strongly suggest that you revisit the design decisions that make it "necessary" ... because there is no way to find all references to an object from within the JVM in which the object lives. – Stephen C Apr 27 '14 at 11:15
  • Not all references "to" an object - all references "from". As I wrote: "I want to list all the objects that are reachable from a certain object". – user3572544 Apr 27 '14 at 11:17
  • What's not working? It looks fine at the first glance. Just move the null-check to the method start, so it works for arrays, too. A side note: AFAIK you don't need `wasAccessible` as what you get is your own copy (which gets GC'd afterwards). – maaartinus Apr 27 '14 at 12:47
  • @maaartinus OK, here is [my code](http://pastebin.com/u7u3VE5X). I wrote a simple test in main function, but the result is totally wrong. I wrote in the comment (lines 61-65) what should be the output. Thank you :) – user3572544 Apr 27 '14 at 13:32
  • Sorry, I don't have a compiler here. But there's nearly nothing fundamentally wrong with your code, just clean it up and it will work. I see a problem: You're using a `Set` for storing referred objects, but the set uses `equals` and you need one which uses `==`. IIRC there's none, but you can simulate it easily by using an `IdentityHashMap`. I'd also suggest to get rid of global variables (`softAllowed` should be an argument). Write a proper test and ignore references until you're sure that the base works. – maaartinus Apr 27 '14 at 20:22

0 Answers0