WeakReferenced объект не собирается после вызова System.gc () - PullRequest
0 голосов
/ 06 июня 2018

Я новый ученик Java.Сейчас я изучаю концепцию WeakReference.Я столкнулся с проблемой, которая выглядит глупо, но я просто хочу выяснить причину.Проблема заключается в следующем: в соответствии с Java-документом, «Слабые ссылочные объекты, которые не препятствуют тому, чтобы их ссылки делались финализируемыми, финализируемыми и затем исправляемыми».

Итак, я выполнил небольшой тест:

import java.lang.ref.WeakReference; 

public class A {
    public static void main(String[] args) {
        A a = new A();
        WeakReference<A> wr = new WeakReference<>(a);
        a = null;

        A a1 = wr.get();

        System.out.println(a);
        System.out.println(a1);

        try {
            System.gc();

            Thread.sleep(10000);

        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(a1);
    }

    @Override
    protected void finalize( ) {
        System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
    }
}

Однако я заметил, что после запуска GC wr.get() может возвращать объект, который я ожидал равным null, и метод finalize() былне вызывается.Так что пошло не так?Спасибо за вашу помощь заранее!:)

Ответы [ 2 ]

0 голосов
/ 16 июня 2018

Во-первых, System.gc() не обеспечивает сборку мусора.Вместо этого это просто подсказка: «Самое время запустить сборку мусора».

Во-вторых, в вашем коде, когда вы ставите A a1 = wr.get(); перед вызовом System.gc(), он создает новую сильную ссылку на тот жеобъект, на который ссылается a, таким образом, даже если сборщик мусора запускается, ваш объект не будет собирать мусор.

Поскольку у нас есть две задачи на руках

  1. Обеспечение сбора мусора
  2. Не сохраняйте сильных ссылок на объект, для которого вы хотите собирать мусор

Давайте внесем небольшие изменения в ваш код

public class A {
    public static void main(String[] args) {
        A a = new A();
        WeakReference<A> wr = new WeakReference<>(a);
        a = null;
        // A a1 = wr.get(); Removing this, this does our 2nd task
        System.out.println(a);
        // System.out.println(a1); Removing this as a1 does not exists anymore
        try {
            while (null != wr.get()) { // 1st task done, the loop ensures sending the hint until your object collected
                System.gc();
                // Thread.sleep(10000); it does not have impact
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(wr.get()); // Obviously prints null
    }

    @Override
    protected void finalize() {
        System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
    }
}
0 голосов
/ 06 июня 2018

Предпосылка вашего теста ошибочна.System.gc() - это всего лишь подсказка для запуска сборщика мусора.Это часто игнорируется.

Из документации :

Вызов метода gc предполагает , что виртуальная машина Java затрачивает усилия на утилизацию неиспользуемых объектов, чтобысделайте память, которую они занимают в настоящее время доступной для быстрого повторного использования.Когда управление возвращается из вызова метода, виртуальная машина Java сделала все возможное, чтобы освободить пространство от всех отброшенных объектов.

(выделение мое)

В будущем вы можете использоватьопции VM -verbose:gc и -XX:+PrintGCDetails, чтобы увидеть, что делает сборщик мусора.


Что еще более важно, вы также очень быстро извлекаете ссылку из слабой ссылкии вернем его обратно в строгую ссылку:

A a = new A();
WeakReference<A> wr = new WeakReference<>(a);
a = null; // no strong references remain
A a1 = wr.get(); // the instance now has a strong reference again

Если между этими двумя точными инструкциями не происходит сборка мусора, объект не будет собирать мусор.

Если вы удалите a1, вашкод вел себя так, как вы ожидаете, когда я его запустил (хотя из-за первой части моего ответа ваш пробег может отличаться):

class A
{
    public static void main(String[] args)
    {
        A a = new A();
        WeakReference<A> wr = new WeakReference<>(a);
        a = null;

        System.out.println(a);

        try {
            System.gc(); // instance of A is garbage collected
            Thread.sleep(10000);

        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(wr.get());
    }

    @Override
    protected void finalize( )
    {
        System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
    }
}
...