2009-03-01 4 views
3

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

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 сделать специальную обработку для целых и других (типов значений с плавающей точкой, длинный, двойной, .. .)?

+1

Я думаю, что int32 - это структура, а не класс. – Shawn

+0

Попробуйте запустить это на 64-битной ОС ... –

+0

, даже тогда платформа сохраняет int как 4 байта. * native int * это другое дело. хотя плохой пример может закончиться с разным значением, я признаю – ShuggyCoUk

ответ

5

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

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

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

15

Нет, факт, что они являются типами значений, не означает, что они хранятся в стеке. Это означает, что они хранятся wherever the variable lives.

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

EDIT: Как указано в комментарии Шона (но я хотел сделать его более очевидным), System.Int32 - это структура, а не класс. (На самом деле, CLR создаст теневой тип ссылки, чтобы покрыть вложенные значения int, но это другое дело.)

+0

Спасибо, Jon, Теперь у меня все в голове. – 2009-03-01 22:10:17

+0

, чтобы быть понятным, если компилятор знает тип переменной, в которой вызывается метод, и указанный метод * непосредственно * определен в этом классе (если виртуальный, то в классе/структуре должно быть переопределение), то описанный вызов в IL содержит всю необходимую информацию, поэтому не требуется бокс – ShuggyCoUk

4

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

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

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

object o = new StringBuilder(); 

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

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

object p = 42; 

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

+0

Для вашего примера StringBuilder два дополнительных указателя являются частью ссылки или объекта? и почему два, а не только один? Спасибо. – 2009-03-01 23:34:00

+0

Нет, восемь байтов не содержат ссылки, они являются частью объекта в куче. Указатель на таблицу виртуальных методов и еще четыре байта, которые не очень хорошо документированы ... Вот еще информация: http://stackoverflow.com/questions/489805/c-reference-variable-mem-allocation – Guffa

+0

Просто быть придирчивым: «если это локальная переменная в методе», и эта переменная не захватывается в закрытие, а метод не является блоком итератора; -p –

0

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

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

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

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