Ссылки этих объектов в стеке или в куче?

Подпишитесь на учетную запись как можно большего числа основных почтовых провайдеров (gmail / yahoo / hotmail / aol / etc). Если вы вносите изменения в свои электронные письма, либо переписываете, либо меняете код, отправляющий электронные письма, либо меняя свои почтовые серверы, и т.д., обязательно отправляйте тестовые сообщения всем своим учетным записям и убедитесь, что они не помечены как спам.

13
задан Omar 5 September 2012 в 20:57
поделиться

8 ответов

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

class A { public int VarA; }
class X
{
    static void Main(string[] args)
    {
        A a1 = new A();
        a1.VarA = 5;
        A a2 = a1;
        a2.VarA = 10;
    }
}

вот что происходит в Microsoft CLR 4.0, работающей под управлением C # 4.0, в режиме отладки.

На этом этапе указатель кадра стека был скопирован в регистр ebp:

Здесь мы выделяем динамическую память для нового объекта.

A a1 = new A();
mov         ecx,382518h 
call        FFE6FD30 

Это возвращает ссылку на объект кучи в eax. Мы сохраняем ссылку в слоте стека ebp-48, который является временным слотом, не связанным ни с каким именем. Помните, что a1 еще не инициализирован.

mov         dword ptr [ebp-48h],eax 

Теперь мы берем эту ссылку, которую мы только что сохранили в стеке, и копируем ее в ecx, который будет использоваться для указателя this на вызов ctor.

mov         ecx,dword ptr [ebp-48h] 

Теперь мы вызываем ctor.

call        FFE8A518 

Теперь мы снова копируем ссылку, хранящуюся во временном слоте стека, в регистр eax.

mov         eax,dword ptr [ebp-48h] 

А теперь мы копируем ссылку из eax в слот стека ebp-40, то есть a1.

mov         dword ptr [ebp-40h],eax 

Теперь мы должны загрузить a1 в eax:

a1.VarA = 5;
mov         eax,dword ptr [ebp-40h] 

Помните, что теперь eax - это адрес данных, выделенных в куче для объекта, на который ссылается a1. Поле VarA этого объекта занимает четыре байта в объекте, поэтому мы сохраняем в нем 5:

mov         dword ptr [eax+4],5 

Теперь мы делаем копию ссылки в слоте стека для a1 в eax, а затем копируем ее в слот стека для a2 , то есть EBP-44.

A a2 = a1;
mov         eax,dword ptr [ebp-40h] 
mov         dword ptr [ebp-44h],eax 

И теперь, как и следовало ожидать, мы снова получаем a2 в eax, а затем используем ссылку на четыре байта для записи 0x0A в VarA:

a2.VarA = 10;
mov         eax,dword ptr [ebp-44h] 
mov         dword ptr [eax+4],0Ah

Итак, ответ на ваш вопрос заключается в том, что ссылки на объект хранятся в стек в трех местах: EBP-44, EBP-48 и EBP-40.Они хранятся в регистрах в eax и ecx. Память объекта, включая его поле, хранится в управляемой куче. Это все на x86 в отладочной сборке Microsoft CLR v4.0. Если вы хотите знать, как данные хранятся в стеке, куче и регистрах в какой-то другой конфигурации, это может быть совершенно иначе. Все ссылки могут храниться в куче или все в регистрах; стека может вообще не быть. Это полностью зависит от того, как авторы jit-компилятора решили реализовать семантику IL.

27
ответ дан 1 December 2019 в 18:06
поделиться
class X 
{ 
    A a1=new A(); // reference on the stack, object value on the heap 
    a1.VarA=5;    // on the Heap- value type (Since it is inside a reference type)
    A a2=a1;      // reference on the stack, object value on the heap 
    a2.VarA=10;   // on the Heap - value type (Since it is inside a reference type)
}
2
ответ дан 1 December 2019 в 18:06
поделиться

Строго говоря, это зависит от реализации. Обычно .NET-разработчик не должен заботиться об этом. Насколько мне известно, в реализации .NET от Microsoft переменные типов значений хранятся в стеке (когда они объявляются внутри метода), а данные объектов ссылочного типа размещаются в управляемой куче. Но помните, когда тип значения является полем класса, данные самого класса хранятся в куче (включая все поля типа значения). Следовательно, не смешивайте семантику (типы значений и ссылки типы) с правилами размещения. Эти вещи могут быть коррелированы, а могут и не быть.

10
ответ дан 1 December 2019 в 18:06
поделиться

Я думаю, у вас может быть небольшое недоразумение ...

Вообще говоря, ссылочные типы хранятся в куче, а типы значений / локальные переменные, как мне кажется (может ошибаться) пойти в стек. Однако ваши примеры A1.VarA и A2.VarA относятся к полю ссылочного типа, которое хранится вместе с объектом в куче ...

2
ответ дан 1 December 2019 в 18:06
поделиться

Для полного понимания этой темы прочитайте книгу Джеффа Рихтера CLR через C#

0
ответ дан 1 December 2019 в 18:06
поделиться

Вспомните чтение в C# in Depth :- Только локальные переменные (объявленные внутри метода) и параметр метода живут в стеке. Переменная экземпляра, как varA в вышеприведенном случае, живет в куче.

0
ответ дан 1 December 2019 в 18:06
поделиться

В этом случае a1.VarA будет в куче, поскольку пространство для него будет выделено, когда вы сделали A a1 = new A () .

Если вы просто выполните int i = 5; в функции, которая будет помещена в стек, но, как вы явно указали, a1 должен был быть размещен в куче, тогда все типы значений, связанные с ним, будут помещены в куче

2
ответ дан 1 December 2019 в 18:06
поделиться

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

0
ответ дан 1 December 2019 в 18:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: