Открыты ли статические поля для сборки мусора?

96

Учитывая гипотетический служебный класс, который используется только при настройке программы:

class MyUtils {
   private static MyObject myObject = new MyObject();
   /*package*/static boolean doStuff(Params... params) {
       // do stuff with myObject and params...
   }
}

будет ли myObject сборщиком мусора, когда он больше не используется, или он останется на всю жизнь программы?

Майкл Дирдеафф
источник

Ответы:

113

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

Ознакомьтесь с разделом JLS 12.7 Выгрузка классов и интерфейсов

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

Бруно Конде
источник
@bruno, по вашей ссылке, означает ли это, что загрузчик классов содержит ссылку на каждый загружаемый класс, даже если загруженный класс не имеет статических членов?
Pacerier
@brunoconde, на самом деле я не думаю, что это правда. В каком именно абзаце это сказано? (Продолжайте обсуждение на stackoverflow.com/questions/405364/… )
Pacerier
Когда загрузчик классов будет иметь право на сборку мусора. ?
Рохит Бандил
@RohitBandil - когда он недоступен.
Stephen C
55

На статические переменные ссылаются объекты класса, на которые ссылается ClassLoaders -so, если либо ClassLoader каким-то образом не отбрасывает класс (если это даже возможно), либо сам ClassLoader становится подходящим для сбора (более вероятно - подумайте о выгрузке веб-приложений) статических переменных (или скорее объекты, на которые они ссылаются) не будут собраны.

Джон Скит
источник
1
На Classобъекты, не содержащие статических переменных, ссылается их загрузчик классов?
Pacerier
14

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

class MyUtils {
   static
   {
      MyObject myObject = new MyObject();
      doStuff(myObject, params);
   }

   static boolean doStuff(MyObject myObject, Params... params) {
       // do stuff with myObject and params...
   }
}

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

Finnw
источник
13

myObject - это ссылка, а не объект . Объект автоматически собирается сборщиком мусора, если на него нет ссылок, потому что он недоступен.

Таким образом, объект за статической ссылкой «myObject» может быть удален сборщиком мусора, если разыменовать его с помощью

myObject = null;

и нет других ссылок на этот объект.

Однако статические ссылки и переменные остаются в течение всего срока службы вашей программы.

Феликс Кейл
источник
Добро пожаловать в StackOverflow! Установка объекта nullв конец static block- жизнеспособный вариант. Однако в моем случае время жизни объекта должно быть больше, чем у статического блока. Конец полезности объекта не был очень конкретным; поэтому мой вопрос об использовании сборщика мусора.
Michael Deardeuff
7

Я думаю, что это ответ на ваш вопрос - в основном, нет, если класс не исходит из специального загрузчика классов, который выгружает класс.

Том
источник
0

Ключевым моментом здесь является сборка мусора экземпляров класса, то есть объектов. Экземпляр ClassLoader, по сути, является объектом. Таким образом, если объект Classloader не является сборщиком мусора, любые ссылки на них, хранящиеся в куче (т.е. статический материал), почти никогда не будут собираться сборщиком мусора. Исключение составляет пул строк.

Поэтому, прежде чем вы вдруг решите сделать, private static MyGiantClass myGiantObject = new MyGiantClass() подумайте дважды, как я узнал на своем собственном опыте.

ha9u63ar
источник