可通过Java中的强引用或弱引用访问的对象

时间:2014-04-25 10:39:37

标签: java weak-references strong-references

我正在与垃圾收集器挣扎。我想列出所有可以从某个对象强或弱地到达的对象。我知道我需要递归地做,但我找不到一种简单的方法来实现它。请你帮助我好吗?

public static List<Object> getAllReachableObjects (Object from)

2 个答案:

答案 0 :(得分:1)

直接的解决方案不应该那么困难,但是......请注意,可以从给定对象到达许多对象....

根据评论编辑:

物体应分为柔软,弱,幻影和强烈可达的物体。这有点复杂。可以手动实现基于图形的优雅解决方案,但我从第一个答案中实际修改了代码。请注意,这尚未经过广泛测试。

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

public class AllReachableObjects
{
    public static void main(String[] args)
    {
        TestObject a = new TestObject("a", null, null, null, null);
        TestObject as = new TestObject("as", a, null, null, null);
        TestObject aw = new TestObject("aw", null, a, null, null);
        TestObject ap = new TestObject("ap", null, null, a, null);
        TestObject ar = new TestObject("ar", null, null, null, a);

        printInfo(new ReachableObjects(as));
        printInfo(new ReachableObjects(aw));
        printInfo(new ReachableObjects(ap));
        printInfo(new ReachableObjects(ar));

        TestObject asr = new TestObject("as", null, null, null, as);
        TestObject ars = new TestObject("as", ar, null, null, null);

        printInfo(new ReachableObjects(asr));
        printInfo(new ReachableObjects(ars));

    }

    private static void printInfo(ReachableObjects r)
    {
        System.out.println("Soft");
        printList(r.getSoftlyReachable());
        System.out.println("Weak");
        printList(r.getWeaklyReachable());
        System.out.println("Phantom");
        printList(r.getPhantomReachable());
        System.out.println("Strong");
        printList(r.getStronglyReachable());
    }

    private static void printList(List<Object> list)
    {
        for (Object object : list)
        {
            System.out.println("    "+object+" (class "+object.getClass()+")");
        }
    }


}


class ReachableObjects
{
    private static final Field REFERENCE_REFERENT_FIELD =
        initReferenceReferentField();

    private static Field initReferenceReferentField()
    {
        try
        {
            return Reference.class.getDeclaredField("referent");
        }
        catch (NoSuchFieldException e)
        {
            e.printStackTrace();
        }
        catch (SecurityException e)
        {
            e.printStackTrace();
        }
        return null;
    }

    private Set<Object> softlyReachable;
    private Set<Object> weaklyReachable;
    private Set<Object> phantomReachable;
    private Set<Object> stronglyReachable;


    public ReachableObjects(Object object)
    {
        softlyReachable = new LinkedHashSet<Object>();
        weaklyReachable = new LinkedHashSet<Object>();
        phantomReachable = new LinkedHashSet<Object>();
        stronglyReachable = new LinkedHashSet<Object>();

        try
        {
            collectAllReachableObjects(object, stronglyReachable, "");
        }
        catch (IllegalArgumentException e)
        {
            e.printStackTrace();
        }
        catch (IllegalAccessException e)
        {
            e.printStackTrace();
        }
        softlyReachable.removeAll(weaklyReachable);
        softlyReachable.removeAll(phantomReachable);
        softlyReachable.removeAll(stronglyReachable);

        weaklyReachable.removeAll(softlyReachable);
        weaklyReachable.removeAll(phantomReachable);
        weaklyReachable.removeAll(stronglyReachable);

        phantomReachable.removeAll(softlyReachable);
        phantomReachable.removeAll(weaklyReachable);
        phantomReachable.removeAll(stronglyReachable);
    }

    private void collectAllReachableObjects(
        Object from, Set<Object> result, String indent) 
        throws IllegalArgumentException, IllegalAccessException
    {
        if (result.contains(from))
        {
            return;
        }
        result.add(from);
        Class<?> c = from.getClass();
        Class<?> leafClass = c;
        while (c != null)
        {
            //System.out.println(indent+"Class "+c);

            Field fields[] = c.getDeclaredFields();
            for (Field field : fields)
            {
                //System.out.println(indent+"Field "+field+" of "+c);

                if (Modifier.isStatic(field.getModifiers()))
                {
                    continue;
                }

                boolean wasAccessible = field.isAccessible();
                field.setAccessible(true);
                Object value = field.get(from);
                if (value != null)
                {
                    Set<Object> nextResult = stronglyReachable;
                    if (field.equals(REFERENCE_REFERENT_FIELD))
                    {
                        if (leafClass.equals(SoftReference.class))
                        {
                            nextResult = softlyReachable;
                        }
                        else if (leafClass.equals(WeakReference.class))
                        {
                            nextResult = weaklyReachable;
                        }
                        else if (leafClass.equals(PhantomReference.class))
                        {
                            nextResult = phantomReachable;
                        }
                    }
                    collectAllReachableObjects(value, nextResult, indent+"  ");
                }
                field.setAccessible(wasAccessible);
            }
            c = c.getSuperclass();
        }
    }

    List<Object> getSoftlyReachable()
    {
        return new ArrayList<Object>(softlyReachable);
    }
    List<Object> getWeaklyReachable()
    {
        return new ArrayList<Object>(weaklyReachable);
    }
    List<Object> getPhantomReachable()
    {
        return new ArrayList<Object>(phantomReachable);
    }
    List<Object> getStronglyReachable()
    {
        return new ArrayList<Object>(stronglyReachable);
    }
}


class TestObject
{
    String name;
    SoftReference<TestObject> softReference;
    WeakReference<TestObject> weakReference;
    PhantomReference<TestObject> phantomReference;
    Object strongReference;

    TestObject(String name, 
        TestObject soft, TestObject weak, TestObject phantom, TestObject strong)
    {
        this.name = name;
        if (soft != null)
        {
            softReference = new SoftReference<TestObject>(soft);
        }
        if (weak != null)
        {
            weakReference = new WeakReference<TestObject>(weak);
        }
        if (phantom != null)
        {
            phantomReference = new PhantomReference<TestObject>(phantom, new ReferenceQueue<>());
        }
        strongReference = strong;
    }
    @Override
    public String toString()
    {
        return name;
    }
}

答案 1 :(得分:1)

不幸的是,这并没有真正起作用。好的,我只想拥有这样的方法:

   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

请记住,对象可以是数组。代码需要类似:

// 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);
相关问题