Шаги в процессе выделения памяти для объектов Java

Что происходит в памяти, когда класс создает экземпляр следующего объекта?

public class SomeObject{

    private String strSomeProperty;

    public SomeObject(String strSomeProperty){
        this.strSomeProperty = strSomeProperty;
    }
    public void setSomeProperty(String strSomeProperty){
        this.strSomeProperty = strSomeProperty;
    }
    public String getSomeProperty(){
        return this.strSomeProperty;
    }
}

В классе SomeClass1:

SomeObject so1 = new SomeObject("some property value");

В классе SomeClass2:

SomeObject so2 = new SomeObject("another property value");

Как выделена память для вновь созданного объекта и его свойств?

Ответ 1

Пусть пройдет через него:

SomeObject so1 = new SomeObject("some property value");

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

String tmp = new String("some property value");
SomeObject so1 = new SomeObject(tmp);
// Not that you would normally write it in this way.

(Чтобы быть абсолютно точным - это не совсем эквивалентно. В оригинале "новая строка" создается во время компиляции и является частью образа .class. Вы можете думать об этом как о хаке производительности.)

Итак, сначала JVM выделяет пространство для String. Обычно вы не знаете или не заботитесь о внутренних функциях реализации String, поэтому просто доверьтесь, что кусок памяти используется для представления "некоторого значения свойства". Кроме того, у вас есть временная выделенная память, содержащая ссылку на String. Во второй форме он явно называется tmp; в вашей первоначальной форме Java обрабатывает его, не называя его.

Далее JVM выделяет пространство для нового SomeObject. Это немного пространства для внутренней бухгалтерии Java и пространства для каждого из полей объекта. В этом случае есть только одно поле, strSomeProperty.

Имейте в виду, что strSomeProperty - это просто ссылка на String. Пока что он будет инициализирован нулевым.

Затем выполняется конструктор.

this.strSomeProperty = strSomeProperty;

Все это делает копию ссылки на строку в поле strSomeProperty.

Наконец, пространство присваивается для ссылки на объект so1. Это задается ссылкой на SomeObject.

so2 работает точно так же.

Ответ 2

Определение использования памяти в Java доктора Хайнца М. Кабуца дает точный ответ, а также программу для расчета использования памяти. Соответствующая часть:

  • Класс занимает не менее 8 байт. Итак, если вы скажете новый Object(); вы выберете 8 байтов в куче.
  • Каждый элемент данных занимает 4 байта, за исключением длинного и двойного, которые занимают 8 байтов. Даже если элемент данных является байтом, он все равно занимает 4 байта! Кроме того, объем используемой памяти увеличивается в 8 байтовых блоках. Итак, если у вас есть класс, содержащий один байт, для этого класса будет 8 байтов и 8 байтов для данных, всего 16 байт (стон!).
  • Массивы немного умнее. Примитивы получаются в массивах, поэтому, если у вас есть массив байтов, каждый из них будет принимать один байт (ничего себе!). Использование памяти, конечно же, продолжается в 8-байтовых блоках.

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

Ответ 3

Баллы для запоминания:

  • Когда вызывается метод, в верхней части стека создается кадр.
  • Как только метод завершил выполнение, поток управления возвращается к вызывающему методу, и его соответствующий стек стека очищается.
  • Локальные переменные создаются в стеке.
  • Переменные экземпляра создаются в куче и являются частью объекта, к которому они принадлежат.
  • В стеке создаются ссылочные переменные.

Ссылка: http://www.javatutorialhub.com/java-stack-heap.html