Объекты, достижимые сильными или слабыми ссылками в Java

1

Я борюсь с сборщиком мусора. Я хочу перечислить все объекты, которые достигают сильно или слабо от определенного объекта. Я знаю, что мне нужно сделать это рекурсивно, но я не могу найти простой способ добиться этого. Не могли бы вы мне помочь?

public static List<Object> getAllReachableObjects (Object from)
  • 0
    Все объекты? Например, объекты на объектах на полях и т. Д.? В противном случае, просто задумчиво проверьте его поля.
  • 0
    Да, все объекты. Я попытался проверить все поля с помощью from.getClass () .getFields (), но не могу заставить его работать. Не могли бы вы предоставить код, показывающий, что вы имеете в виду?
Теги:
weak-references
strong-references

2 ответа

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);
  • 0
    Вы правы насчет массивов. Я пришел к такому же выводу. Однако код зацикливания массива будет нуждаться в проверке на ноль, а вызов collectAllReachableObjects приведет к его сбою.
1

Решение straighforward не должно быть так сложно, но... обратите внимание, что может быть много объектов, доступных из данного объекта....

EDIT на основе комментария:

Объекты должны быть разделены на softly-, weakly-, phantom- и объекты с высокой степенью достижимости. Это немного сложнее. Можно было бы реализовать элегантное решение на основе графиков вручную, но я прагматически модифицировал код из первого ответа. Обратите внимание, что это не было протестировано широко.

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;
    }
}
  • 0
    Большое спасибо за ответ! Это помогло, но я хотел бы задать еще один вопрос. Можно ли создать четыре списка, содержащих только мягкие ссылки, только слабые ссылки, только фантомные ссылки и только сильные ссылки? Это было бы просто идеально. Знаете ли вы, как изменить свой код для достижения этого?
  • 0
    @ user3572544 Да, задавать вопрос - это искусство (закатывая глаза). Вы упомянули, что «боретесь со сборщиком мусора». Что бы вы ни подразумевали под этим: вы НЕ должны использовать такую программу для обнаружения утечек памяти или около того. Используйте профилировщик для этого. Профилировщик выполняет инструментарий через агента и предоставляет достоверную информацию. Для случая ссылок: Вы никогда не знаете, является ли или почему определенный «референт» null , поэтому информация, предоставляемая таким служебным классом, может быть только очень сомнительным «снимком» определенного состояния программы.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню