Как ссылки на объекты C # представлены в памяти / во время выполнения (в CLR)? - PullRequest
12 голосов
/ 29 февраля 2012

Мне любопытно узнать, как ссылки на объекты C # представляются в памяти во время выполнения (в .NET CLR).Некоторые вопросы, которые приходят на ум:

  1. Сколько памяти занимает ссылка на объект?Отличается ли оно, когда оно определено в области видимости класса и области видимости метода?Отличается ли оно в зависимости от области видимости (стек и куча)?

  2. Какие фактические данные хранятся в ссылке на объект?Это просто адрес памяти, который указывает на объект, на который он ссылается, или это нечто большее?Отличается ли это в зависимости от того, определено ли оно в рамках класса или метода?

  3. Те же вопросы, что и выше, но на этот раз, когда речь идет о ссылке на ссылку, например, когдассылка на объект передается методу по ссылке.Как меняются ответы на вопросы 1 и 2?

Ответы [ 2 ]

14 голосов
/ 29 февраля 2012

.NET кучи и стеки Это подробное описание работы стека и кучи.

C # и многие другие языки ООП, использующие кучу, для общего использования в качестве справочного языка Обрабатывает не указатели для ссылок в этом контексте (C # также может использовать указатели!) Аналогии с указателями работают для некоторыхобщие понятия, но эта концептуальная модель не подходит для таких вопросов, как это.См. Отличный пост Эрика Липперта на эту тему Дескрипторы не являются адресами

Нельзя говорить, что дескриптор - это размер указателя. (хотя это может совпадатьбыть одинаковыми) Дескрипторы являются псевдонимами для объектов, не обязательно, чтобы они были формальным адресом объекта.

В этом случае CLR использует реальные адреса для дескрипторов: по приведенной выше ссылке:

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

Так что да, дескриптор, вероятно, составляет 4 байта в 32-битной архитектуре и 8 байтов в 64-байтовой архитектуре, но это не «наверняка», и это не напрямуюиз-за указателей .Стоит отметить, что в зависимости от реализации компилятора и используемых диапазонов адресов некоторые типы указателей могут различаться по размеру .

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

Окончательный вариант этой тонкой точки:

Это C #Указатель:

int* myVariable;

Это дескриптор C #:

object myVariable;

Они не одинаковы.

Вы можете делать такие вещи, как математикана указатели, что вы не должны делать с ручками.Если ваш дескриптор реализован как указатель, и вы используете его как указатель, то вы неправильно используете дескриптор, что может впоследствии привести к неприятностям.

14 голосов
/ 29 февраля 2012

Этот ответ легче понять, если вы понимаете указатели C / C ++.Указатель - это просто адрес памяти некоторых данных.

  1. Ссылка на объект должна иметь размер указателя, который обычно составляет 4 байта на 32-битном процессоре и 8 байтовна 64-битном процессоре.Это то же самое, независимо от того, где оно определено.Где оно живет, зависит от того, где оно определено.Если это поле класса, оно будет находиться в куче объекта, частью которого он является.Если это статическое поле, оно находится в специальном разделе кучи, который не подлежит сборке мусора.Если это локальная переменная, она живет в стеке.

  2. Ссылка на объект - это просто указатель, который можно представить как int или long, содержащий адрес объекта в памяти.,Это то же самое, независимо от того, где оно определено.

  3. Это реализовано как указатель на указатель.Данные одинаковые - просто адрес памяти.Однако по указанному адресу памяти нет объектов.Вместо этого есть другой адрес памяти, который является исходной ссылкой на объект.Это то, что позволяет изменить опорный параметр.Обычно параметр исчезает, когда его метод завершается.Поскольку ссылка на объект не является параметром, изменения в этой ссылке сохранятся.Ссылка на ссылку исчезнет, ​​но не ссылка.Это цель для передачи ссылочных параметров.

Одна вещь, которую вы должны знать, типы значений хранятся на месте (нет адреса памяти, вместо этого они хранятся непосредственно там, где адрес памяти будетбыть - см. № 1).Когда они передаются в метод, создается копия, и эта копия используется в методе.Когда они передаются по ссылке, передается адрес памяти, который находит тип значения в памяти, позволяя изменить его.

Редактировать: Как указывал dlev, эти ответы не являются жестким и быстрым правилом, посколькунет правила, которое гласит, что так и должно быть..NET может свободно реализовывать эти вопросы так, как хочет.Хотя это наиболее вероятный способ его реализации, поскольку именно так работает процессор Intel для внутреннего использования, поэтому использование любого другого метода, вероятно, будет неэффективным.

Надеюсь, я вас не слишком смущал, но не стесняйтесьспросить, нужны ли вам разъяснения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...