垃圾收集器是否在Enum类型上运行?

Vis*_*ant 33 java enums

根据jls§8.9.2Enum Body声明

枚举声明声明终结器是编译时错误.枚举类型的实例可能永远不会最终确定.

由于终结器在垃圾收集器运行之前执行,如果终结器不存在,这是否意味着enum类型始终保持在内存中,并且垃圾收集器不适用于enum类型?

Edw*_*rzo 39

如果编译枚举就好

enum Suit {SPADES, HEARTS, CLUBS, DIAMONDS}
Run Code Online (Sandbox Code Playgroud)

您将看到生成的字节码(即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();
}
Run Code Online (Sandbox Code Playgroud)

因此,枚举的实例是类本身的静态成员.然后我认为这可能是垃圾收集的唯一方法是,如果类本身是垃圾收集的,如果它是由系统类加载器加载的话,这是不太可能发生的.

  • @assylias我说"不太可能",文件说"可能永远不会最终确定".我猜你的情况是可能的,如果这个类实际上是卸载的,并且如果你足够幸运,gc运行. (2认同)
  • @assylias - 除非同时卸载加载它的类加载器,否则永远不会卸载类.因此,除非枚举是由自定义类加载器加载的,否则它实际上永远不会被卸载(即使它在概念上是不可加载的). (2认同)

Bhe*_*ung 14

垃圾收集器是否在Enum类型上运行?

只是一个实验来证明枚举实例可以符合gc条件.

定义样本枚举如下 -

public enum SampleEnum { ONE; }
Run Code Online (Sandbox Code Playgroud)

和测试代码 -

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!");
Run Code Online (Sandbox Code Playgroud)

尝试使用该-verbose:gc选项.


由于终结器在垃圾收集器运行之前执行,如果终结器不存在,这是否意味着枚举类型始终保持在内存中,垃圾收集器不适用于枚举类型?

实际上,终结器的存在/不存在与任何对象是否将被gc'ed无关.枚举实例不是gc'ed,因为它们由编译器生成的枚举类中的静态字段引用.