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

Собирает ли сборщик мусора тип Enum?

Согласно jls § 8.9.2 Объявить объявления тела

Это ошибка времени компиляции объявления enum для объявления финализатора. Экземпляр типа перечисления никогда не может быть завершен.

Поскольку финализатор выполняется непосредственно перед запуском Garbage Collector, если финализатор отсутствует, это означает, что тип enum всегда остается загруженным в память, а сборщик мусора не применим к типу enum?

4b9b3361

Ответ 1

Если вы скомпилируете перечисление типа

enum Suit {SPADES, HEARTS, CLUBS, DIAMONDS}

Вы увидите, что сгенерированные байт-коды (т.е. javap -p Suit) соответствуют синтетическому классу:

final class Suit extends java.lang.Enum<Suit> {
  public static final Suit SPADES;
  public static final Suit HEARTS;
  public static final Suit CLUBS;
  public static final Suit DIAMONDS;
  private static final Suit[] $VALUES;
  public static Suit[] values();
  public static Suit valueOf(java.lang.String);
  private Suit();
}

Итак, экземпляры перечисления являются статическими членами самого класса. Тогда я думаю, что единственным способом, с помощью которого можно было собрать мусор, было бы, если бы сам класс был собран мусором, что очень маловероятно, если оно было загружено загрузчиком системного класса.

Ответ 2

Запускает ли сборщик мусора на тип Enum?

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

Определите образец перечисления следующим образом:

public enum SampleEnum { ONE; }

И тестовый код -

Class<SampleEnum> clazz = SampleEnum.class;
String[] fieldNames = {
    "ONE", "ENUM$VALUES"
};
//create a weak reference to the instance
WeakReference<SampleEnum> ref = new WeakReference<SampleEnum>(SampleEnum.ONE);
//remove the hard references
for (String fieldName: fieldNames) {
    Field feld = clazz.getDeclaredField(fieldName);
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(feld, feld.getModifiers() & ~Modifier.FINAL);
    feld.setAccessible(true);
    feld.set(null, null);
}
//wait until a gc occurs and clears the weak ref
while (ref.get() != null) {
    System.out.println("Waiting ...");
    System.gc();
}
//output just to verify that the weak ref is cleared by the gc
System.out.println("Weak reference is cleared!");

Попробуйте с опцией -verbose:gc.


Поскольку финализатор выполняется непосредственно перед запуском Garbage Collector, если финализатор отсутствует, это означает, что тип перечисления всегда остается загруженным в память, а сборщик мусора не применим для типа перечисления?

Собственно, наличие/отсутствие финализатора не имеет никакого отношения к тому, будет или нет какой-либо объект быть gc'ed. Экземпляры перечисления не являются gc'ed, потому что на них ссылаются статические поля в классе enum, сгенерированном компилятором.

Ответ 3

Я считаю, что поскольку типы перечисления и перечисления всегда статичны, он будет вести себя так, как если бы это был статический член, поскольку он мог быть доступен в любое время.

Дополнительно финализаторы предназначены для вызова, когда объект выгружается из памяти, поскольку они предназначены для выполнения любой необходимой операции очистки, и вы не можете создавать объекты Enum's.

Ответ 4

Это любопытная пара предложений.

Это ошибка времени компиляции объявления enum для объявления финализатора.

Это достаточно ясно. Я не знаю, почему это так, но правила - это правила. Это также похоже на то, что перечисления происходят из Enum, а спецификация API говорит, что Enum имеет финализатор final.

Экземпляр типа перечисления никогда не может быть завершен.

Язык здесь кажется мне двусмысленным. Объявляют ли они, что ни один экземпляр типа enum никогда не будет завершен? Если да, то почему "может"? Почему бы просто не сказать так? Они просто напоминают нам, что завершение не гарантируется? В любом случае, это не имеет значения....

Object finalize метод определен, чтобы ничего не делать (12.6). Enum происходит от Object, а перечисления выводятся из Enum. Enum Финализатор не определен, чтобы что-либо сделать, и вы не можете его переопределить, поэтому, когда вы объединяете все это, финализация экземпляра перечисления не имеет никаких эффектов.

В моей интерпретации экземпляры перечисления могут быть собраны в мусор (хотя, как указывали другие, обстоятельства, позволяющие это произойти, несколько необычны), и поскольку их метод finalize не предназначен, чтобы ничего не делать, а метод finalize всегда называется спорным.