Что случилось со статической памятью в Java? - PullRequest
19 голосов
/ 01 января 2009

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

Мой вопрос: как заполнена эта статическая память? Статический объект помещается в статическую память при импорте или при первом обращении? Кроме того, применяются ли к статическим объектам те же правила сбора мусора, что и ко всем остальным объектам?


public class Example{
    public static SomeObject someO = new SomeObject();
}
/********************************/
// Is the static object put into static memory at this point?
import somepackage.Example;

public class MainApp{
    public static void main( Sting args[] ){
// Or is the static object put into memory at first reference?
       Example.someO.someMethod();
// Do the same garbage collection rules apply to a 
//     static object as they do all others?
       Example.someO = null;
       System.gc();
    }
}

Ответы [ 6 ]

34 голосов
/ 01 января 2009

Импорт не коррелирует с инструкциями в скомпилированном коде. Они устанавливают псевдонимы для использования только во время компиляции.

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

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

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


В качестве (тангенциального) бонуса необходимо рассмотреть один сложный вопрос:

public class Foo {
  private static Foo instance = new Foo();
  private static final int DELTA = 6;
  private static int BASE = 7;
  private int x;
  private Foo() {
    x = BASE + DELTA;
  }
  public static void main(String... argv) {
    System.out.println(Foo.instance.x);
  }
}

Что будет печатать этот код? Попробуйте, и вы увидите, что он печатает «6». Здесь есть несколько вещей, и один из них - порядок статической инициализации. Код выполняется так, как если бы он был написан так:

public class Foo {
  private static Foo instance;
  private static final int DELTA = 6;
  private static int BASE;
  static {
    instance = null;
    BASE = 0;
    instance = new Foo(); /* BASE is 0 when instance.x is computed. */
    BASE = 7;
  }
  private int x;
  private Foo() {
    x = BASE + 6; /* "6" is inlined, because it's a constant. */
  }
}
5 голосов
/ 01 января 2009

Обычно не существует такого понятия, как «статическая» память. Большинство виртуальных машин имеют постоянную генерацию кучи (куда загружаются классы), которая обычно не собирается мусором.

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

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

3 голосов
/ 01 января 2009

Инициализация статических переменных описана в разделе 2.11 Статические инициализаторы спецификации JVM солнц. Однако спецификация не определяет реализацию сборки мусора, поэтому я предполагаю, что правила сборки мусора для статических объектов будут различаться в зависимости от вашей виртуальной машины.

3 голосов
/ 01 января 2009

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

Вы можете проверить это, создав статический блок инициализатора. Поместите точку останова в этот блок инициализатора, и вы увидите, когда он будет вызван. Или еще проще ... поставить точку останова в конструкторе SomeObject.

2 голосов
/ 02 января 2009

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

Таким образом, объект, на который ссылается указатель, находится в обычной куче, как и любой другой объект.

0 голосов
/ 02 января 2009

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

Он также может быть освобожден (даже если не обнулен), если сам класс выгружен и весь граф объектов вырезан из кучи. Конечно, когда класс может быть выгружен, это хорошая тема для множества других вопросов ...:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...