.Net / C #: каков реальный размер целого числа? - PullRequest
3 голосов
/ 02 марта 2009

в .Net, целые числа являются типами значений, что означает, что они хранятся в стеке. Целые числа также являются классами (обычно System.Int32). У них есть методы, такие как CompareTo, Equals, ... Таким образом, они должны занимать более четырех байтов в стеке. Приведенный ниже пример показывает, что они занимают ровно 4 байта:

unsafe static void Main()
{
    int a = 2, b = 4;
    Console.WriteLine("Adress of a : {0}", (int)&a);
    Console.WriteLine("Adress of b : {0}", (int)&b);
    Console.WriteLine("Size of integer: {0}", (int)(&a) - (int)(&b));
}

Выход:

Adress of a : 1372876
Adress of b : 1372872
Size of integer: 4

Делает ли CLR специальную обработку для целочисленных и других типов значений (float, long, double, ...)?

Ответы [ 4 ]

15 голосов
/ 02 марта 2009

Нет, тот факт, что они являются типами значений, не означает, что они хранятся в стеке. Это означает, что они хранятся везде, где живет переменная .

Но, эй, давайте разберемся с бизнесом локальной переменной, и в этот момент (без перехватов и т. Д.) Они do живут в стеке. И они занимают 4 байта. Почему они берут больше? Нет необходимости в vtable в стеке, потому что метаданные уже указывают тип: нет никакой двусмысленности относительно того, какие виртуальные методы будут вызываться и т. Д.

РЕДАКТИРОВАТЬ: Как указано в комментарии Шона (но я хотел сделать это более очевидным), System.Int32 является структурой, а не классом. (На самом деле CLR создаст ссылочный тип тени, чтобы охватить упакованные значения целых, но это другой вопрос.)

5 голосов
/ 02 марта 2009

Таким образом, они должны занимать более четырех байтов в стеке.

Это не следует. Среда выполнения компилятора и знает точный тип. Типы значений не могут быть далее подтипированы, поэтому нет необходимости в «vtable» или другом объектно-специфическом динамическом механизме диспетчеризации.

Когда типы значений упакованы в кучи, требуется обычный заголовок .NET Object.

4 голосов
/ 02 марта 2009

Тип значения выделяется в стеке, если это локальная переменная в методе. Если тип значения является членом класса, он будет выделен как часть области памяти объекта в куче.

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

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

object o = new StringBuilder();

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

Тип значения также может быть упакован, то есть сохранен как объект в куче. Это происходит, когда вы приводите тип значения к объекту:

object p = 42;

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

0 голосов
/ 20 мая 2011

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

// type definition
public class Bla {}
// instance of type bla
public Bla myBla = new Bla();

по сути размер int такой, какой кажется (4 байта), но, как вы выяснили, это размер пространства памяти, которое требуется для объявления.

Определение типа хранится в другом месте, такие методы, как CompareTo, объявляются таким образом только один раз, а не один раз для каждого экземпляра того типа, который вы объявляете, и поскольку они загружаются как часть самих библиотек инфраструктуры, для целей вашего приложения. эти определения фактически занимают 0 места.

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