Статьи

Java Secret: загрузка и выгрузка статических полей

ОБЗОР

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

Однако может быть удивительным узнать, что статические поля живут в куче, могут иметь любое количество копий и очищаются GC, как и любой другой объект.

Это следует из предыдущего обсуждения; Статические блоки интерпретируются?

ЗАГРУЗКА СТАТИЧЕСКИХ ПОЛЕЙ

Когда для связывания получен класс, это может не привести к инициализации статического блока.

Простой пример

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
public class ShortClassLoadingMain {
    public static void main(String... args) {
        System.out.println("Start");
        Class aClass = AClass.class;
        System.out.println("Loaded");
        String s= AClass.ID;
        System.out.println("Initialised");
    }
}
 
class AClass {
    static final String ID;
    static {
        System.out.println("AClass: Initialising");
        ID = "ID";
    }
}

печать

1
2
3
4
Start
Loaded
AClass: Initialising
Initialised

Вы можете видеть, что можете получить ссылку на класс до того, как он будет инициализирован, только когда он используется, он инициализируется.

ЗАГРУЗКА НЕСКОЛЬКИХ КОПИЙ СТАТИЧЕСКОГО ПОЛЯ

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

РАЗГРУЗКА СТАТИЧЕСКИХ ПОЛЕЙ

статические поля выгружаются, когда ClassLoader Class выгружается. Это выгружается, когда выполняется сборщик мусора и нет сильных ссылок из стеков потоков.

ПОМЕЩЕНИЕ ДВУХ КОНЦЕПТОВ ВМЕСТЕ

Вот пример, где класс печатает сообщение, когда оно инициализируется и когда его поля завершаются.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
class UtilityClass {
    static final String ID = Integer.toHexString(System.identityHashCode(UtilityClass.class));
    private static final Object FINAL = new Object() {
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println(ID + " Finalized.");
        }
    };
 
    static {
        System.out.println(ID + " Initialising");
    }
}

Загружая этот класс повторно, дважды за раз

01
02
03
04
05
06
07
08
09
10
11
for (int i = 0; i < 2; i++) {
  cl = new CustomClassLoader(url);
  clazz = cl.loadClass(className);
  loadClass(clazz);
 
  cl = new CustomClassLoader(url);
  clazz = cl.loadClass(className);
  loadClass(clazz);
  triggerGC();
}
triggerGC();

вы можете увидеть результат, как это

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
1b17a8bd Initialising
2f754ad2 Initialising
 
-- Starting GC
1b17a8bd Finalized.
-- End of GC
 
6ac2a132 Initialising
eb166b5 Initialising
 
-- Starting GC
6ac2a132 Finalized.
2f754ad2 Finalized.
-- End of GC
 
 
-- Starting GC
eb166b5 Finalized.
-- End of GC

В этом журнале две копии класса загружаются первыми. Ссылки на первый класс / загрузчик классов перезаписываются ссылками на второй класс / загрузчик классов. Первый очищается на GC, второй сохраняется. Во втором цикле инициализируются еще две копии. Четвертый сохраняется, второй и третий очищаются на GC. Наконец, четвертая копия статических полей очищается в GC, когда они больше не являются ссылками.

КОД

Первый пример — ShortClassLoadingMain Второй пример — LoadAndUnloadMain

Ссылка: Java Secret: загрузка и выгрузка статических полей от нашего партнера JCG Питера Лоури из Vanilla Java .

Статьи по Теме: