Подтвердить что ты не робот

Как один вызов `finalize` нарушает GC/JVM?

При исследовании Почему ThreadPoolExecutor ведет себя по-другому при запуске Java-программы в Eclipse и из командной строки? Я написал тест, который вызывает очень странный OutOfMemoryError (max mem = 256 Mb )

class A {
    byte[] buf = new byte[150_000_000];

    protected void finalize() {
        int i = 1;
    }
}

A a1 = new A();
a1 = null;
A a2 = new A();

закомментировать int i = 1, и тест работает. Насколько я понимаю, когда finalize пуст, HotSpot просто игнорирует его. Но как может быть только один практически пустой finalize вызов break GC/JVM?

4b9b3361

Ответ 1

Но как может только один пустой финализированный вызов прерывать GC/JVM?

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

В этом коде:

A a1 = new A();
a1 = null;
A a2 = new A();

... GC будет вызываться на последней строке, чтобы попытаться найти достаточно памяти для выделения второго A. К сожалению, он не может мусор собирать первый A (и массив, на который он ссылается), потому что финализатор еще не запущен. Он не дожидается завершения финализатора, а затем попытается снова собрать мусор - он просто бросает OutOfMemoryError.