Когда я создаю объект, выделяется ли свежая память для полей и методов экземпляра или только для полей экземпляра

14

У меня следующий класс

class Student{

int rollNumber;
int marks;

public void setResult(int rollNumber, int marks){

    this.rollNumber=rollNumber;
    this.marks=marks;   
}

public void displayResult(){

    System.out.println("Roll Number= "+this.rollNumber+"   Marks= "+this.marks);

}
}

Теперь я создаю два объекта типа Student следующим образом

Student s1=new Student();
Student s2=new Student();

Теперь два разных набора памяти выделены для полей экземпляра. Теперь мой вопрос заключается в том, выделяется ли память для методов ( setResultи displayResult) дважды или один раз?

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

введите описание изображения здесь

Harish_N
источник
1
Совместное использование ваших исследований помогает всем . Расскажите нам, что вы пробовали и почему это не соответствует вашим потребностям. Это свидетельствует о том, что вы потратили время, чтобы попытаться помочь себе, избавляет нас от повторения очевидных ответов и, прежде всего, помогает получить более конкретный и актуальный ответ. Также см. Как спросить
Gnat
3
Я изучаю Java ... и во всех материалах они просто говорят, что всякий раз, когда мы создаем объект, свежая память выделяется для всех полей экземпляра ... но ни в одном из материалов не сказано, будет ли выделена свежая память для методов или нет
Harish_N

Ответы:

13

Код для методов является частью Class(более кратко Class<Student>) и загружается в память при первой загрузке класса.

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

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

SJuan76
источник
Ok. Теперь я на 90% уверен. Но небольшое сомнение. Предположим, что если я создаю 10 объектов типа Student, то только 1 набор свежей памяти выделяется для методов, присутствующих в классе Student, тогда как 10 наборов свежей памяти выделено для хранения переменных экземпляра для 10 объектов .. Я прав?
Harish_N
Правильно. Подумайте, что память занимают не только свойства, но и небольшой экземпляр, связанный с самим экземпляром (экземпляр класса без свойств будет использовать более 0 байт памяти).
SJuan76
Еще одна вещь ... Я задал вопрос, имея в виду Java ... То же самое происходит в Java .....
Harish_N
Спецификация языка Java ничего не говорит о том, сколько памяти выделяется, когда и для какой цели. Это остается за реализатором, и каждый реализатор может выбирать по-своему.
Йорг Миттаг,
6

Поля экземпляра (включая поля поддержки свойств) получают N-копии для N-объектов.

Статические поля получают одну копию для каждого класса.

Методы - это блоки байт-кода (или после JIT, блоки нативных инструкций), которые являются частью «образа» программы или сегмента исполняемого кода. Методы уже являются частью образа программы, поскольку она находится на диске. Как только изображение загружено ОС (или CLR), существует одна общая копия кода метода.

Они не являются частью "кучи" или выделения времени выполнения в целом, за исключением случаев, когда вы можете использовать размещаемый компилятор для компиляции новых методов на лету. Методы не «распределяются» как объекты и не «распределяются» относительно создания объекта. Они просто существуют как часть программы, прежде чем когда-либо будет создан единственный объект. Даже лямбды / делегаты не распределяются на лету. Компилятор создает классы по требованию для реализации этих других, казалось бы, динамических объектов кода, и они также существуют как часть образа байт-кода на диске.

ОБНОВЛЕНИЯ за комментарии:

Стандарт JVM имеет следующее:

2.5.4. Область метода

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

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

Таким образом, ясно, что (1) да, спецификация не диктует, как это делается, но (2) она аналогична области хранения для скомпилированного кода обычного языка, т.е. текстовый сегмент. Это точка, которую я делаю.

codenheim
источник
То, что вы говорите, имеет смысл, но действительно ли это гарантировано JLS? Как правило, JLS дает разработчикам много возможностей для решения подобных вопросов.
Йорг Миттаг,
Не уверен в этом, @ JörgWMittag. Вы можете быть правы. Пункт, который я попытался сделать, заключается в том, что «new T ()» не выделяет новый экземпляр метода. Что касается специфики JVM, загрузчики классов действительно хранят байт-код в куче, и я предполагаю, что существуют возможные сценарии, когда сами классы создаются и даже собираются. Но это деталь реализации среды выполнения, и концептуально, куча, о которой я говорю, - это куча «пользователя». Класс и методы не считаются данными в обычном пользовательском контексте. Но так как мы также можем управлять загрузчиком классов из пользовательского пространства, я не знаю.
Коденхайм,
JLS даже не говорит о куче, не так ли? Совершенно законно реализовать Java с динамическим стеком и без кучи вместо конечного стека фиксированного размера и динамической кучи. JLS также ничего не говорит о JVM, это совершенно справедливо для реализации Java без JVM.
Йорг Миттаг,
Вы ссылаетесь на JLS, но я говорю на JVM. Стандарт JVM определенно обсуждает кучу. Вы должны предоставить переменную область действия / время жизни, которая выходит за пределы локальной области стека. Что касается того, что теоретически возможно, я предпочитаю думать в терминах «известных реализаций». Я почти уверен, что реализация полной JVM без примитива кучи - сложная или даже невозможная работа, поскольку JVM не является чисто стековой машиной. Мое понимание машин Forth и других чистых стековых архитектур состоит в том, что это возможно, если существует примитив для произвольного доступа к переменным, но я просто не видел его.
Коденхайм,
@ JörgWMittag - я добавил к ответу кое-что, что может представлять интерес для нашего обсуждения. Дело в том, что я проводил аналогию с традиционным кодом или текстовым сегментом в обычных системах времени выполнения.
Коденхайм,
-4

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

Абхишек Трипати
источник
1
Похоже, это просто повторяет информацию, предоставленную в предыдущих ответах.