声明一个简单类型的变量是否只分配内存?

时间:2015-08-30 11:20:31

标签: c# variables declaration

我在C中阅读了this question,我在C#中遇到了同样的问题。

通过代码说

是否正确
int a;
在初始化之前,

a保留了四个未分配的字节?或初始化是第一次分配字节的地方?

4 个答案:

答案 0 :(得分:4)

没有赋值的int声明(如注释中所述)将被编译器优化掉 - 它不会在程序中显示出来。

假设你在函数中(而不是类型定义)并分配int,那么当函数开始时,分配将从堆栈空间进行(也就是说,int是从已经专用于该线程的内存中分配的,并且不会导致操作系统分配)。

另一方面,如果int是类型定义的一部分(并且被使用),那么它将增加该类型的每个实例的分配空间,无论该类型最终被分配(堆类,堆或者结构的堆栈取决于使用情况。)

在任何情况下都不会导致int本身的指针或引用。

进一步解释:

原始问题是指一个例子。 int是一个固定长度(4字节)的数据结构,因此编译器注意到包含有关声明的方法将需要4个字节来存储它。编译器将在为当前线程的方法局部变量(调用堆栈)保留的内存区域中保留4个字节,而不是在堆上分配这4个字节(它放置引用类型)并产生垃圾收集开销。 。当线程启动时,该内存已从操作系统中分配,并且仅为该线程保留。如果线程用完该空间,则称其为堆栈溢出。

值得注意的是,.NET确实有2个编译器 - 将C#代码转换为IL的C#编译器,以及在运行时将IL转换为机器指令的JIT编译器。在我的回答中,当我说"编译器"时,我正在做一些关于我的意思的编译器,但结果是一样的。

根据评论,如果我这样做......

void Foo() {
  {
    int a = 5;
    Console.WriteLine(a);
  }
  {
    int a = 7;
    Console.WriteLine(a);
  }
}

...然后编译器可能会重新使用为第一个变量a分配的堆栈空间,因为它们在语义上是不同的。但这是一种优化。

还值得注意的是,调用堆栈除了方法局部变量之外还包括其他信息 - 它包括方法的参数,返回值的空间(如果函数返回引用类型,则为指针),以及返回地址。

最后,我在C#中添加了JIT编译器可以内联的方法 - 这意味着可以将被调用方法的代码批量复制到调用者的主体中,以避免方法的开销呼叫。在这种情况下,堆栈帧也将包含被调用方法的局部变量的空间。

答案 1 :(得分:2)

C#中的int总是4个字节(无论值是多少)。

请记住

int a;

相同
int a = 0;

声明int时,默认值为0

答案 2 :(得分:1)

嗯,这取决于变量类型 由于int是ValueType,因此它分配所需的所有4个字节。 在c#中有两个主要类别的变量:引用类型和值类型。在值的情况下类型如int所有变量分配所需的内存但在使用new运算符之前声明引用类型的变量时它只分配一个指针和创建主对象后,它分配存储变量所需的空间。

Class MyType
{
...
}

MyType s; // Just a pointer
s=new MyType(); //Now allocating happens.

有关参考类型的更多信息,请参阅MSDN Reference Types 有关值类型的更多信息,请参阅MSDN Value Types

MSDN:

  

C#中有两种类型:引用类型和值类型。   引用类型的变量存储对其数据(对象)的引用,   而值类型的变量直接包含它们的数据。同   引用类型,两个变量可以引用同一个对象;   因此,对一个变量的操作可能会影响引用的对象   由另一个变量。对于值类型,每个变量都有自己的变量   数据的副本,并且不可能对其进行操作   变量影响另一个(除了ref和out之外)   参数变量,请参阅ref (C# Reference)out parameter modifier (C# Reference))

答案 3 :(得分:-3)

在您使用 new 关键字创建对象之前,示例中的变量的简单声明将包含引用。