Вопрос о фрейме стека: Java против C++

Q1. В Java все объекты, массивы и переменные класса хранятся в куче? Верно ли то же самое для C++? Является ли сегмент данных частью кучи?

Как насчет следующего кода на C++?

class MyClass{
    private:
            static int counter; 
            static int number;
};

MyClass::number = 100;

Q2. Насколько я понимаю, переменные, которым компилятор присвоил определенное значение, хранятся в сегменте данных, а неинициализированные глобальные и статические переменные хранятся в BSS (блок, запускаемый символом). В этом случае MyClass::counter, будучи статическим, инициализируется компилятором нулем, поэтому он сохраняется в BSS, а MyClass::number, который инициализируется значением 100, сохраняется в сегменте данных. Правильно ли я делаю вывод?

Q3. Рассмотрим следующий фрагмент кода:

void doHello(MyClass &localObj){   
// 3.1 localObj is a reference parameter, where will this get stored in Heap or Stack?
      // do something
}

void doHelloAgain(MyClass localObj){   
// 3.2 localObj is a parameter, where will this get stored in Heap or Stack?
      // do something
}

int main(){
      MyClass *a = new MyClass();  // stored in heap

      MyClass localObj;   
      // 3.3 Where is this stored in heap or stack?
      doHello(localObj);
      doHelloAgain(localObj);
}

Я надеюсь, что я ясно изложил свои вопросы для всех

ИЗМЕНИТЬ:

Пожалуйста, обратитесь к этой статье, чтобы получить некоторое представление о BSS.

EDIT1: имя класса изменено с MyInstance на MyClass, так как это было неудачное имя. Искренние извинения

EDIT2: номер переменной члена класса изменен с нестатического на статический.


person pankajt    schedule 26.08.2009    source источник
comment
Каждый раз, когда вы вызываете new, вы используете malloc, а это означает, что все, что вы создаете с помощью new, действительно хранится в куче. Я понятия не имею, что вы подразумеваете под тем, что сегмент данных является частью кучи?   -  person Matt Ball    schedule 26.08.2009
comment
МойКласс::число = 100; не будет компилироваться. Ты хотел сказать счетчик?   -  person Kevin Panko    schedule 26.08.2009
comment
изменил номер переменной-члена на статический   -  person pankajt    schedule 26.08.2009


Ответы (5)


Это несколько упрощено, но в основном точно, насколько мне известно.

В Java все объекты размещаются в куче (включая все ваши переменные-члены). Большинство других вещей (параметров) являются ссылками, а сами ссылки хранятся в стеке вместе с собственными типами (целые, длинные и т. д.), за исключением строки, которая является скорее объектом, чем собственным типом.

В C++, если бы вы размещали все объекты с помощью ключевого слова «new», это была бы почти такая же ситуация, как в java, но в C++ есть один уникальный случай, потому что вместо этого вы можете размещать объекты в стеке (вы не всегда нужно использовать "новый").

Также обратите внимание, что производительность кучи Java ближе к производительности стека C, чем производительность кучи C, сборщик мусора делает довольно умные вещи. Это все еще не так хорошо, как стек, но намного лучше, чем куча. Это необходимо, поскольку Java не может размещать объекты в стеке.

person Bill K    schedule 26.08.2009
comment
хорошая информация о производительности кучи java и сравнении производительности стека c - person pankajt; 26.08.2009
comment
Все объекты Java хранятся в куче, да. Переменные объекта хранят ссылки на них. Примитивные переменные (int, float, bool и т. д.) хранят свои собственные значения; они не ссылки. Параметры метода передаются по значению. - person Kevin Panko; 26.08.2009
comment
На данный момент я действительно презираю всю терминологию передачи по значению/ссылке и стараюсь не использовать ее. В Java проще всего просто помнить, что при работе с объектами у вас всегда есть ссылка, вы никогда не передаете фактический объект. Сказать, что это не Pass By Reference, сбивает с толку любого, кто пытается понять, как работает язык (даже если это правда), поэтому я полностью отказался от терминологии. - person Bill K; 27.08.2009
comment
@Devil Jin Да, способ, которым Java выполняет выделение кучи, не требует каких-либо действий по распределению для освобождения памяти для недолговечных объектов (именно так C выполняет выделение стека - один возврат извлекает все объекты стека одновременно) . Есть несколько официальных документов, которые действительно приятно читать. - person Bill K; 27.08.2009

Q1

Java также хранит переменные в стеке, но экземпляры классов размещаются в куче. В C++ вы можете размещать экземпляры классов либо в стеке, либо в куче. Используя ключевое слово new, вы размещаете экземпляр в куче.

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

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

Вопрос 2

MyClass::number хранится там, где размещен экземпляр класса MyClass. Это может быть либо в куче, либо в стеке. Обратите внимание на Q3, как a указывает на экземпляр MyClass, размещенный в куче, в то время как localObj размещается в стеке. Таким образом, a->number находится в куче, а localObj.number — в стеке.

Поскольку MyClass::number является переменной экземпляра, вы не можете назначить ее следующим образом:

MyClass::number = 100;

Однако вы можете назначить MyClass::counter, так как он статический (за исключением того, что он частный):

MyClass::counter = 100;

Вопрос 3

Когда вы вызываете doHello, переменная localObjmain) передается по ссылке. Переменная localObj в doHello ссылается на эту переменную в стеке. Если вы измените его, изменения будут сохранены в стеке, где выделено localObj в main.

Когда вы вызываете doHelloAgain, переменная localObjmain) копируется в стек. Внутри doHelloAgain переменная localObj размещается в стеке и существует только на время вызова.

person Martin Liversage    schedule 26.08.2009
comment
Q3: Ссылки, как и указатели, представляют собой 32-битные (обычно) значения, содержащие адрес памяти. Это идет в стек в doHello. Класс MyInstance имеет размер 8 байт (при условии, что int — 32 бита), и он помещается в стек в doHelloAgain. - person Kevin Panko; 26.08.2009

В C++ объекты могут размещаться в стеке... например, localObj в вашей основной процедуре Q3.

Я чувствую некоторую путаницу в отношении классов и экземпляров. «MyInstance» имеет больше смысла как имя переменной, чем имя класса. В вашем примере Q1 «число» присутствует в каждом объекте типа MyInstance. «счетчик» является общим для всех экземпляров. "MyInstance::counter = 100" является допустимым присвоением, а "MyInstance::number = 100" - нет, потому что вы не указали, какому объекту должен быть назначен член "number".

person Jim Lewis    schedule 26.08.2009

Q1. В Java все объекты, массивы и переменные класса хранятся в куче? Верно ли то же самое для C++? Является ли сегмент данных частью кучи?

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

Объекты находятся в куче только тогда, когда вы используете ключевое слово new или что-то из семейства функций malloc.

Q2. Насколько я понимаю, переменные, которым компилятор присвоил определенное значение, хранятся в сегменте данных, а неинициализированные глобальные и статические переменные хранятся в BSS (блок, запускаемый символом). В этом случае MyInstance::counter, будучи статическим, инициализируется компилятором нулем, поэтому он сохраняется в BSS, а MyInstance::number, который инициализируется значением 100, сохраняется в сегменте данных. Правильно ли я делаю вывод?

Да, вы правильно понимаете раздел BSS. Однако, поскольку number не является статическим, код:

MyInstance::number = 100;

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

Q3. Рассмотрим следующий фрагмент кода: ...

void doHello(MyInstance &localObj){

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

void doHelloAgain(MyInstance localObj){

копия переданного параметра помещается в стек.

MyInstance localObj;
// 3.3 Where is this stored in heap or stack?

localObj находится в стеке.

person Evan Teran    schedule 26.08.2009
comment
объекты могут быть размещены в стеке. Я согласен с этим, но так ли это в случае с java? - person pankajt; 26.08.2009
comment
Нет, java размещает в стеке только примитивы и ссылки, а не объекты. - person nos; 26.08.2009

Все области памяти в C++ перечислены здесь

person Tadeusz Kopec    schedule 26.08.2009