仅仅声明一个简单类型的变量会分配内存吗?
Does just declaring a variable of a simple type allocates memory?
我在 C 中阅读 this question,我在 C# 中有同样的问题。
代码说的对吗
int a;
初始化前为a
预留了四个未分配的字节?或者初始化是第一次分配字节的地方?
C# 中的 int
始终为 4 个字节(无论值是什么)。
记住
int a;
与
相同
int a = 0;
当声明一个int
时,它被赋予默认值0
。
像您的示例中那样的简单变量声明将包含一个引用,直到您使用 new 关键字创建一个对象。
嗯,这取决于变量类型。
由于 int 是一个 ValueType,它分配了所有需要的 4 个字节。
c# 中有两大类变量:引用类型和值 Types.In 值类型的情况,例如 int 分配变量所需的所有内存,但是当您在使用 new 运算符之前声明引用类型的变量时,它只是分配一个指针,并在创建主对象后分配存储变量所需的 space。
Class MyType
{
...
}
MyType s; // Just a pointer
s=new MyType(); //Now allocating happens.
有关引用类型的详细信息,请参阅 MSDN Reference Types。
有关值类型的更多信息,请参阅 MSDN Value Types。
MSDN:
There are two kinds of types in C#: reference types and value types.
Variables of reference types store references to their data (objects),
while variables of value types directly contain their data. With
reference types, two variables can reference the same object;
therefore, operations on one variable can affect the object referenced
by the other variable. With value types, each variable has its own
copy of the data, and it is not possible for operations on one
variable to affect the other (except in the case of ref and out
parameter variables, see ref (C# Reference) and out parameter modifier
(C# Reference)).
没有赋值的 int 声明(如评论中所述)将被编译器优化掉——它根本不会出现在程序中。
假设您在函数中(与类型定义相反)并分配 int,分配将从堆栈开始 space 当函数开始时(即 int 从内存中分配)已经专用于该线程,不会导致 OS 分配)。
另一方面,如果 int 是类型定义的一部分(并被使用),那么它将增加该类型的每个实例的分配 space,无论该类型最终被分配到哪里( 类 的堆,结构的堆或堆栈,具体取决于用途)。
在任何情况下,它都不会导致 int 本身的指针或引用。
一些进一步的解释:
原题举例指的是int。 int 是固定长度(4 字节)的数据结构,因此编译器注意到包含相关声明的方法需要 4 个字节来存储它。编译器不会在堆上(放置引用类型的地方)分配这 4 个字节并产生垃圾回收开销,而是在为当前线程的方法局部变量(调用堆栈)保留的内存区域中保留 4 个字节。该内存是在线程启动时从 OS 分配的,并且只为该线程保留。如果线程用完那个 space,它被称为堆栈溢出。
这里值得注意的是,.NET 确实有 2 个编译器——将 C# 代码转换为 IL 的 C# 编译器,以及在运行时将 IL 转换为机器指令的 JIT 编译器。在我的回答中,当我说 "the compiler" 时,我正在对我确切指的是哪个编译器进行一些操作,但结果是一样的。
根据评论,如果我这样做...
void Foo() {
{
int a = 5;
Console.WriteLine(a);
}
{
int a = 7;
Console.WriteLine(a);
}
}
... 那么编译器可能会重新使用为第一个变量 a
分配的堆栈 space 第二个变量,因为它们在语义上是不同的。但这是一个优化。
还值得注意的是,调用堆栈包括方法局部变量之外的其他信息 - 它包括方法的参数,space 用于 return 值(如果函数 returns 是引用类型),还有 return 地址。
最后,我要补充一点,在 C# 中,您的方法可能会被 JIT 编译器内联 - 这意味着被调用方法的代码可能会被复制到调用者的主体中,以避免方法的开销称呼。在这种情况下,堆栈帧也将包括 space 用于被调用方法的局部变量。
我在 C 中阅读 this question,我在 C# 中有同样的问题。
代码说的对吗
int a;
初始化前为a
预留了四个未分配的字节?或者初始化是第一次分配字节的地方?
C# 中的 int
始终为 4 个字节(无论值是什么)。
记住
int a;
与
相同int a = 0;
当声明一个int
时,它被赋予默认值0
。
像您的示例中那样的简单变量声明将包含一个引用,直到您使用 new 关键字创建一个对象。
嗯,这取决于变量类型。
由于 int 是一个 ValueType,它分配了所有需要的 4 个字节。
c# 中有两大类变量:引用类型和值 Types.In 值类型的情况,例如 int 分配变量所需的所有内存,但是当您在使用 new 运算符之前声明引用类型的变量时,它只是分配一个指针,并在创建主对象后分配存储变量所需的 space。
Class MyType
{
...
}
MyType s; // Just a pointer
s=new MyType(); //Now allocating happens.
有关引用类型的详细信息,请参阅 MSDN Reference Types。
有关值类型的更多信息,请参阅 MSDN Value Types。
MSDN:
There are two kinds of types in C#: reference types and value types. Variables of reference types store references to their data (objects), while variables of value types directly contain their data. With reference types, two variables can reference the same object; therefore, operations on one variable can affect the object referenced by the other variable. With value types, each variable has its own copy of the data, and it is not possible for operations on one variable to affect the other (except in the case of ref and out parameter variables, see ref (C# Reference) and out parameter modifier (C# Reference)).
没有赋值的 int 声明(如评论中所述)将被编译器优化掉——它根本不会出现在程序中。
假设您在函数中(与类型定义相反)并分配 int,分配将从堆栈开始 space 当函数开始时(即 int 从内存中分配)已经专用于该线程,不会导致 OS 分配)。
另一方面,如果 int 是类型定义的一部分(并被使用),那么它将增加该类型的每个实例的分配 space,无论该类型最终被分配到哪里( 类 的堆,结构的堆或堆栈,具体取决于用途)。
在任何情况下,它都不会导致 int 本身的指针或引用。
一些进一步的解释:
原题举例指的是int。 int 是固定长度(4 字节)的数据结构,因此编译器注意到包含相关声明的方法需要 4 个字节来存储它。编译器不会在堆上(放置引用类型的地方)分配这 4 个字节并产生垃圾回收开销,而是在为当前线程的方法局部变量(调用堆栈)保留的内存区域中保留 4 个字节。该内存是在线程启动时从 OS 分配的,并且只为该线程保留。如果线程用完那个 space,它被称为堆栈溢出。
这里值得注意的是,.NET 确实有 2 个编译器——将 C# 代码转换为 IL 的 C# 编译器,以及在运行时将 IL 转换为机器指令的 JIT 编译器。在我的回答中,当我说 "the compiler" 时,我正在对我确切指的是哪个编译器进行一些操作,但结果是一样的。
根据评论,如果我这样做...
void Foo() {
{
int a = 5;
Console.WriteLine(a);
}
{
int a = 7;
Console.WriteLine(a);
}
}
... 那么编译器可能会重新使用为第一个变量 a
分配的堆栈 space 第二个变量,因为它们在语义上是不同的。但这是一个优化。
还值得注意的是,调用堆栈包括方法局部变量之外的其他信息 - 它包括方法的参数,space 用于 return 值(如果函数 returns 是引用类型),还有 return 地址。
最后,我要补充一点,在 C# 中,您的方法可能会被 JIT 编译器内联 - 这意味着被调用方法的代码可能会被复制到调用者的主体中,以避免方法的开销称呼。在这种情况下,堆栈帧也将包括 space 用于被调用方法的局部变量。