2017-01-17 3 views
1

Рассмотрим следующий классJava вывоз мусора из частного поля

public class A { 
    private final Map<Integer, HeavyObject> cache; 
    public HeavyObject getThing(); 
} 

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

У меня есть основания полагать, что это не так, если посмотреть на кучу, есть случаи, когда экземпляры A освобождаются, а HeavyObject в конечном итоге приводит к остановке JVM для большого количества GC.

Адрес одного из комментариев. getThing() вызывается в функции вида:

void compute(A a) { 
    ... 
    while(condition) { 
    ... 
    HeavyThing thing = a.getThing(); 
    ... 
    } 
} 

Так что никакого способа HeavyThing не выходит из времени.

Жизненный цикл является

Set<A> theAs = new HashSet(); 
while(true) { 
    for(int i = 0; i < 16; i++) theAs.add(new A()); 
    theAs = computeNewAs(theAs); 
} 

Обратите внимание, что хитрый бит, что computeNewAs всегда держит 8 экземпляров из старого набора. Так что, глядя на распределение памяти в какой-то момент, я вижу всегда 8 экземпляров A, но огромное количество HashMaps и HeavyObject

+0

Какой GC (G1 или CMS) вы используете? Кроме того, следует отметить, что порядок освобождения может быть произвольным. –

+0

Если экземпляр больше не доступен, он в конечном итоге будет собран. Но есть много способов утечки экземпляров, которые на самом деле не очевидны. Возможно, вы захотите предоставить минимальный пример, который фактически создает утечку памяти. –

ответ

1

Я думаю, может быть, вы в замешательстве.

Кажется, что ваша проблема не в том, будет ли карта cache получить gc'ed, это то, будет ли HeavyObject получить gc'ed. И ваши HeavyObjects определенно может просочиться

public HeavyObject getThing(); 
+0

Добавлены некоторые пояснения, спасибо – NotAUser

1

Вы можете проверить это с помощью следующего кода:

Map<Integer, HeavyObject> cache = new HashMap<Integer, HeavyObject>(){ 
    @Override 
    public void finalize() { 
     System.out.println("I'm gone"); 
    } 
}; 
System.gc(); 
1

Модификатор доступа полей совершенно не имеет значения. Неважно, ссылаются ли ссылки «утечка», когда объект, владеющий полем, недоступен. В этот момент ничто не может просачиваться больше, и все, что имеет значение, - это то, имеет ли «просочился», или в более правильных терминах, доступен ли объект по-прежнему.

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

Что касается вашего наблюдения, это трудно сказать какой вы на самом деле наблюдения, но в коде вы в курсе, нет HashMap ни HeavyObject экземпляр когда-либо созданных, так что его не достаточно, чтобы сказать, является ли это разумное наблюдение. Но если экземпляр A содержит ссылку на HashMap, потенциально содержащий несколько экземпляров HeavyObject, совершенно правдоподобно, что существует значительно больше HeavyObject экземпляров, чем A экземпляров. Если это противоречит вашим ожиданиям, вы должны пересмотреть дизайн.

Если вы подозреваете утечку памяти, вы должны использовать инструмент для профилирования, например.JVisualVM, который поставляется вместе с JDK, и позволяет создавать кучу дампа и искать ожидающие экземпляры и проверять фактические ссылки на эти объекты.

Смежные вопросы