Подсчет эталонных целей в дампе кучи Set‹WeakReference›

В настоящее время я смотрю на дамп кучи этого глупого маленького тестового класса (взятого в самом конце метода main):

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));
        }
    }
}

Теперь я пытаюсь понять, как подсчитать количество ссылок на определенный класс в objects. Если бы это была база данных SQL, это было бы легко:

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;

Результат:

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

После некоторых исследований я решил, что могу создать Eclipse MAT OQL, который дает мне задействованные классы:

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

Увы, это не включает их количество, и OQL, похоже, не поддерживает предложение GROUP BY. Любые идеи, как получить эту информацию?

Отредактировано для добавления: На самом деле ни один из объектов, добавленных в Set (и, очевидно, сама реализация Set), не находится под моим контролем. Извините, изменение RefObj1 и RefObj2 запрещено.

Edit2: я нашел этот связанный вопрос об использовании OQL в jvisualvm но оказывается, что OQL на самом деле является Javascript, высвобожденным на дампе кучи. Меня бы тоже что-то подобное устроило. Но игра с ним пока не дала результатов для меня. Я обновлю вопрос, если это изменится.


person mabi    schedule 10.06.2014    source источник


Ответы (3)


  1. Откройте представление гистограммы (для этого есть кнопка на панели инструментов, которая выглядит как гистограмма).
  2. В первой строке представления гистограммы, где указано «Regex», введите WeakReference, чтобы отфильтровать представление.
  3. Найдите строку java.lang.ref.WeakReference, щелкните правой кнопкой мыши и выберите «Показать объекты по классу» -> «По исходящим ссылкам».
  4. Результирующее представление должно суммировать объекты, на которые ссылаются, сгруппированные по классам, как вам нужно. В столбце «Объекты» должно быть указано количество экземпляров для каждого класса.
person JimN    schedule 10.06.2014
comment
Я соглашусь с этим, если вы сделаете его исходящим (потому что WeakReference.referent кажется исходящим в моей версии). - person mabi; 11.06.2014

Вы можете просто написать метод в объекте, который возвращает информацию и вызвать его из Eclipse...

Поскольку вы не можете изменить объект, следующим лучшим решением будет написать служебную функцию в каком-либо методе, который вы можете изменить, и вызвать его из отладчика eclipse. Я недостаточно хорошо знаю Eclipse, чтобы помочь вам сделать это, не вставляя что-то в исходный код, извините.

person Tim B    schedule 10.06.2014
comment
Спасибо, что указали на это, но, к сожалению, в моей реальности все не так просто. Я обновил вопрос, чтобы отразить это. - person mabi; 10.06.2014
comment
@mabi Обновил мой ответ, но если это вам не поможет, вам нужен эксперт по Eclipse :) - person Tim B; 10.06.2014
comment
Хм, да, внедрение кода в моем сценарии затруднено (иначе мне не понадобился бы дамп кучи для начала;) - person mabi; 10.06.2014

Я бы использовал Weak HashSet. Вы можете просто использовать set.size(), чтобы получить количество еще живых ссылок.

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());
}

Я ожидаю, что это напечатает 0, 1 или 2 в зависимости от того, как очищаются объекты.

person Peter Lawrey    schedule 10.06.2014
comment
Я явно хренов в описаниях проблем. У меня есть только дамп кучи, сгенерированный в конце main, и я хочу реконструировать содержимое objects. Получить общий размер легко (просто взглянув на поля HashMap), но я застрял в погружении в содержимое поля Set. Я обновил вопрос, чтобы (надеюсь) сделать его более ясным. - person mabi; 11.06.2014