Сначала позвольте мне исправить ваши ошибки.
Когда оператор new () используется со ссылочным типом, пространство для экземпляра выделяется в куче, а сама ссылочная переменная помещается в стек.
Ссылка, которая является результатом "new", является значением , а не переменной . Значение относится к месту хранения.
Ссылка, конечно, возвращается в регистр процессора . Копируется ли когда-либо содержимое этого регистра ЦП в стек вызовов, решает оптимизатор джиттера. Это никогда не должно жить в стеке; он может жить вечно в регистрах, или он может быть скопирован непосредственно из реестра в управляемую кучу, или, в небезопасном коде, он может быть скопирован непосредственно в неуправляемую память.
Стек - это деталь реализации. вы не знаете , когда используется стек, если только вы не посмотрите на приведенный код.
Переменная p находится в стеке, а созданный экземпляр Person (все его члены) - в куче. p.id будет 0, а p.name будет нулевым.
Правильно, хотя, конечно, снова p может быть реализован как регистр, если джиттер так решит. Нет необходимости использовать стек, если есть доступные регистры.
Вы, кажется, довольно одержимы идеей, что стек используется. Джиттер может иметь в своем распоряжении большое количество регистров, и эти регистры могут быть довольно большими.
Я из C ++ фона.
Ах, это объясняет, почему вы так зациклены на этом стеке, как куча вещей. Научитесь перестать беспокоиться об этом. Мы разработали среду управляемой памяти, где вещи живут столько, сколько им нужно. Независимо от того, выберет ли менеджер использование стека, кучи или регистров для эффективного управления памятью, зависит от него.
В первой строке переменная someDate размещается в стеке. Точно 12 байтов.
Давайте предположим, ради этого, что эта 12-байтовая структура размещена в стеке. Кажется разумным.
Мой вопрос: что происходит во второй строке? Что делает оператор new ()? Он только обнуляет членов структуры Date или также выделяет пространство в куче?
Вопрос предполагает ложную дихотомию и, следовательно, на него невозможно ответить, как указано. В этом вопросе представлены две альтернативы, или ни одна из них, ни одна из которых не обязательно верна.
С одной стороны, я не ожидал бы, что new выделит место в куче, конечно, потому что в первой строке память уже выделена в стеке для экземпляра структуры.
Правильный вывод, правдоподобные рассуждения. Выделение кучи не выполняется , поскольку компилятор знает, что ни одна часть этой операции не требует долговременного хранилища . Вот для чего куча; Когда компилятор определяет, что данная переменная может жить дольше, чем активация текущего метода, он генерирует код, который выделяет хранилище для этой переменной в долговременном хранилище «куча». Если он определяет, что переменная определенно имеет короткое время жизни, то он использует стек (или регистры) в качестве оптимизации.
С другой стороны, я ожидал бы, что new выделит место в куче и обратный адрес этого пространства, потому что это то, что должен делать новый.
Неправильно. «new» не гарантирует, что куча выделена. Скорее, «новый» гарантирует, что конструктор вызывается в обнуленной памяти.
Вернемся к вашему вопросу:
Он только обнуляет элементы структуры Date или также выделяет пространство в куче?
Мы знаем, что он не выделяет место в куче. Обнуляет ли это членов структуры даты?
Это сложный вопрос. В спецификации сказано, что происходит, когда вы говорите
someDate = new Date();
- определяется адрес someDate
- выделено место (вне "стека") для нового объекта.Обнуляется.
- , затем вызывается конструктор, если таковой имеется, причем "this" является ссылкой на новое хранилище стека
- , тогда байты нового хранилища стека копируются по адресу someDate.
Теперь, это действительно то, что происходит ?Вы были бы совершенно в своем праве заметить, что невозможно сказать , выделено ли новое пространство стека, инициализировано и скопировано, или инициализировано "старое" пространство стека.
ответ заключается в том, что в тех случаях, когда компилятор считает, что пользователь не может заметить, что существующее пространство стека изменяется, существующее пространство стека изменяется, а дополнительное выделение и последующее копирование исключаются .
В тех случаях, когда компилятор не может это сделать, создается временный слот стека, инициализируется нулями, создается, мутируется конструктором, а затем результирующее значение копируется в переменную. Это гарантирует, что если конструктор выдает исключение, вы не сможете наблюдать несогласованное состояние в переменной.
Более подробную информацию об этой проблеме и ее анализе компилятором см. В моей статье на эту тему..
http://blogs.msdn.com/b/ericlippert/archive/2010/10/11/debunking-another-myth-about-value-types.aspx