JavaRush/Java блог/Random/Сколько нужно плохих объектов, чтобы заработал finalize()...

Сколько нужно плохих объектов, чтобы заработал finalize()? Интересные/бесполеные факты

Статья из группы Random
участников
После прочтения лекции 6 level о методе finalize() стало интересно: сколько должно быть мусорных объектов, чтобы рандомный finalize() начал работать? Статья по программированию первая, буду рад вашим пояснениям по нераскрытым топикам в статье. Здесь опишу результат, полученный опытным путём. Придётся убивать котов. Уровень на момет написания статьи - 6. На истину не претендую Обязательно чекните комментарии. После прочтения лекции 6 level о методе finalize() стало интересно: сколько должно быть мусорных объектов, чтобы рандомный finalize() начал работать? Статья по программированию первая, буду рад вашим пояснениям по нераскрытым топикам в статье. Здесь опишу результат, полученный опытным путём. Придётся убивать котов. Сколько нужно плохих объектов, чтобы заработал finalize()? Интересные/бесполеные факты - 1Для эксперимента были использованы два онлайн компилятора. Ресурсы моего компьютера низкие, а на онлайн компиляторе надежда на мощность серверов. Как базовый в работу был взят Online Java Compiler. И такой код:
public class Cat {
   public static int count;
	public static void main(String[] args) {
		for (count = 0; count< 1000000; count++) {
                     Cat cat = new Cat();
                }
	}
	 Cat() { }
	protected void finalize() throws Throwable{
        System.out.println("Я убил кота номер " + count);
    }
}
Далее совершаем первый запуск и... компилятор оказался крайне кровожадным! 16 431 кота зарезал, выбирая рандомно начиная с 622 946 кота. Далее делаем ещё 5 запусков: 708 убитых котов, 25, 1158, 370 и все начинаются примерно с номера 630к +-15к. Также интересно, что концовка ооочень часто выглядит так:

Я убил кота номер 999255
Я убил кота номер 999615
Я убил кота номер 999743
Я убил кота номер 999789
Я убил кота номер 999864
Я убил кота номер 999902
Я убил кота номер 1000000
Я убил кота номер 1000000
Я убил кота номер 1000000
Я убил кота номер 1000000
Я убил кота номер 1000000
Я убил кота номер 1000000
Я убил кота номер 1000000
Откуда повторяющиеся номера, если номер после каждого цикла уникален? Пока ответа не ясен. После закрыл все лишние вкладки в браузере (вдруг на что-то повлияет). Результат следующих 4 тестов примерно такой же. Для чистоты эксперимента применим другой онлайн компилятор с тем же кодом. У него есть ограничение в 183 строки, выводимых на экран, но первые значения всё-такие есть. Тот же около 630 000 номер кота, но уже второго и далее, а вот первый в пяти случаях из пяти оказывался кот около 252 000. А что думаете вы по результатам эксперимента?
Комментарии (4)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Евгений
Уровень 15
12 мая 2020, 22:23
Метод finalize() начиная с java 9 объявлен deprecated. Не используйте метод finalize(). Если необходимо произвести очистку ресурсу после сборки мусора, то необходимо воспользоваться другими средствами: Java 8 и более ранние версии: Использовать PhantomRefrece и RefrenceQueue; Java 9 и более поздние версии: Использовать класс java.lang.ref.Cleaner Больше информации по теме нежелательности использования метода finalize() в этом видео: https://youtu.be/K5IctLPem0c
Justinian Judge в Mega City One Master
5 мая 2020, 23:24
public class Solution {
    public static void main(String[] args) {
        for (int i = 0; i < 1_000_000; i++) {
            new Cat();
        }
        System.out.println("End of cycle");
        System.out.println("Finalize count = " + Cat.getFinalizeCount());
    }
}

class Cat {
    private static int count;
    private static int finalizeCount;

    public Cat() {
        count++;
    }

    protected void finalize() throws Throwable {
        finalizeCount++;
        System.out.println("Я убил кота номер " + count);
    }

    public static int getFinalizeCount() {
        return finalizeCount;
    }
}
смотрим вывод:
Я убил кота номер 999968
Я убил кота номер 999986
Я убил кота номер 1000000
End of cycle
Finalize count = 14374
Я убил кота номер 1000000
Я убил кота номер 1000000
Я убил кота номер 1000000
после строки End of cycle было еще 142 штуки строк Я убил кота номер 1000000. Понятно почему. Поскольку переменная статическая, то есть котов мы завершили создавать. Переменная count застыла на значении 1_000_000, а метод finalize продолжает отрабатывать, он берет переменную count, а там застывшее значение 1_000_000. То есть строка "Я убил кота номер " неверна. Она показывает число для совершенно другого кота. Она кота вообще никакого не показыват вернее, она просто берет последнее значение количество созданных котов.
Justinian Judge в Mega City One Master
5 мая 2020, 23:28
Если же сделать так, чтобы finalize показывал именно номер кота, которого уничтожает:
class Cat {
    private static int totalCount;
    private static int finalizeCount;
    private int number;

    public Cat() {
        number = totalCount++;
    }

    protected void finalize() throws Throwable {
        finalizeCount++;
        System.out.println("Я убил кота номер " + number);
    }

    public static int getFinalizeCount() {
        return finalizeCount;
    }
}
то мы получим вывод:
...
Я убил кота номер 611209
Я убил кота номер 611208
End of cycle
Я убил кота номер 483812
Я убил кота номер 483813
Я убил кота номер 483814
...
Я убил кота номер 484459
Finalize count = 9093
Я убил кота номер 484460
..
На момент выполнения последней строки в мейне, метод Finalize был выполнен 9 093 раз Всего метод finalize был выполнен 11 357 раз. При каждом перезапуске эти цифры будут отличаться. Но повторяющихся строк уже не будет, поскольку мы работаем не с общей для всех котов переменной, а с конкретным номером кота. Также,
Ресурсы моего компьютера низкие, а на онлайн компиляторе надежда на мощность серверов.
не рассчитывай что бесплатные онлайн-ресурсы предоставят тебе какие-то супермощности серверов. Тебе выделяют какой-то кусочек общей памяти, кусочек процессорных мощностей. В среднем, +/- будет соответствовать мощности среднего компьютера и то, при условии что там не будет ограничений. Поэтому работай со своим компьютером, если он не старше чем 12-14 лет конечно. Но в целом, все что нужно понять, что мы не можем знать когда и сколько раз этот метод будет вызван и для каких объектов.
Justinian Judge в Mega City One Master
5 мая 2020, 23:51
Ну и собственно вопрос из названия темы. Сколько нужно плохих объектов, вернее, когда в нашей программе начнет вызываться метод finalize? Для этого чуть модифицируем метод:
protected void finalize() throws Throwable {
    System.out.println("Destroying cat number = " + number);
    System.out.println("Total cats created = " + totalCount);
    System.out.println("Finalize count = " + finalizeCount);
    finalizeCount++;
}
1-ый запуск
Destroying cat number = 52783
Total cats created = 255125
Finalize count = 0
2-й запуск
Destroying cat number = 11273
Total cats created = 254968
Finalize count = 0
3-й запуск
Destroying cat number = 91030
Total cats created = 249458
Finalize count = 0
То есть на этих условных котиках, в районе создания 250-тысячного кота, впервые применяется этот метод. Но снова-таки, не рассчитывай что до этого момента предыдущие коты живы, GarbageCollector живет своей жизнью, finalize своей, они пересекаются в разных местах, но не более. Плюс мы говорим за уровень JVM, а там многие вещи зависят как от версии и типа самой JVM, так и версии и типа самого garbage collector. Неплохо расписано основные моменты здесь, если прочитать все комментарии. https://stackoverflow.com/questions/2506488/when-is-the-finalize-method-called-in-java