C# 内存分配问题?
t1(引用变量)何时会在编译时或运行时获得内存。C# 内存分配问题?,c#,.net,oop,memory-management,C#,.net,Oop,Memory Management,t1(引用变量)何时会在编译时或运行时获得内存。 我想应该是运行时。但当我在Main方法上放置断点并监视t1时,它是空的。这意味着t1在内存中 如果我错了,请纠正我 编辑:我听说静态成员变量是在编译时分配的。不,这意味着t1尚未分配。一旦调用new Test()t1,就会分配内存来存储Test对象的大小,并分配一个内存地址 是,内存仅在运行时分配。内存仅在运行时分配(在编译时,应用程序未运行) 在运行时,t1变量只有在赋值发生后才有一个值(即不为null),因此它取决于断点的位置。如果您将断点放
我想应该是运行时。但当我在Main方法上放置断点并监视t1时,它是空的。这意味着t1在内存中 如果我错了,请纠正我
编辑:我听说静态成员变量是在编译时分配的。不,这意味着t1尚未分配。一旦调用
new Test()
t1,就会分配内存来存储Test
对象的大小,并分配一个内存地址
是,内存仅在运行时分配。内存仅在运行时分配(在编译时,应用程序未运行) 在运行时,
t1
变量只有在赋值发生后才有一个值(即不为null
),因此它取决于断点的位置。如果您将断点放在Main
方法的右大括号上,并在它被击中时检查watch窗口,您将明白我的意思
也就是说,如果您将断点放在赋值行
test1t1=newtest1()代码>则该行尚未执行,因此赋值未发生。在主方法的堆栈框架上指定了引用t1,即您分配给它的值(即“new Test()”部分)是在运行时在堆上分配的-这就是为什么t1变量在该行执行之前存在并且为空。在调试模式下运行应用程序,F5主要是visual studio中的键盘快捷键。在此语句处放置断点。使用F10单步执行下一个语句。调试器执行下一个语句时,您将看到正在创建的对象
public static void Main()
{
Test t1 = new Test();
}
这部分仅为引用分配足够的空间(在许多情况下可能是4字节,但我认为这实际上取决于.NET framework实现),并且在编译时确定,并在调用Main时分配(我认为)
Test t1;
该行在运行时将分配足够的空间来存储测试对象的数据,然后分配现有的引用变量t1来引用新分配的内存。现在已经分配了t1的空间和new Test()的空间
编辑:为了响应您的编辑,静态成员变量不同,而局部变量的行为也不同。然而,我不相信静态成员变量是在编译时分配的。我认为它们是在加载包含它们的类型时分配的(这似乎是在调用引用该类型的任何函数时)
此代码将在调用包含对类型Test2的任何引用的函数后立即创建一个新的Test实例。在“Main”的开头,该实例的堆内存尚未分配(直到new Test()
)。它将保持分配状态,直到垃圾被回收
Test t1;
引用堆内存的局部变量testt1
(基于堆栈)确实存在(并且在“Main”执行的整个时间内都存在)
这两种都是运行时分配,但在内存驻留的位置和驻留时间方面有所不同
静态字段是在加载类型时分配的(从加载类型到首次使用类型之间的某段时间初始化)
对于“编译时”,我不确定您是否指的是JIT编译,但无论采用哪种方式,内存都是与编译分开分配的。您应该能够自己解决这个问题。想想看:
- 当你分配内存时,你“使用”了内存
- 不运行的程序不使用内存
- 运行的程序使用内存
- 在运行时,表示程序正在运行
- 在运行时使用、分配内存
分配内存编译时间,根本没有任何意义…阅读了上述答案后,让我尝试以更好的方式表达答案
让我们这样来解释代码:
class Test2
{
public static Test f1 = new Test();
}
现在,让我们开始:
将调试点放在{,Test t1,t1=new Test()和}
运行程序
让语句{execute-名称t1没有任何内容-为什么
程序正在运行。
这项汇编是多年前完成的。
仍然-t1从未分配内存。为什么
转到下一个调试点,让语句testt1
执行
现在检查-您将发现t1存在于局部变量/内存列表中
为什么?语句被处理并被运行/运行/执行。因此,它被分配了内存
现在-分配了什么内存?它只是引用/指针/对象所需的内存。
它的值应该是空的。那么-你认为它需要多少内存
现在执行下一条语句
这一次,null的值被其他值替换,这确实占用了可变的内存量,具体取决于它的用途
处理下一条语句:
现在发生的情况是对象不再存在/或不再被引用
是否仍为仍然存在的对象分配内存/为其分配的内存
newtest()
为测试t1分配的内存?–是
这个内存继续保留,但幸运的是,垃圾收集器存在并清除垃圾
从效率的角度来看,最好设置Test t1=null
,这样,如果main函数有很多其他语句要处理,那么它就可以通过向垃圾收集器发出不再需要该数据块的信号来取消分配为新Test()分配的内存
在Main
(或变量的作用域)的末尾,垃圾收集器将检查指针是否引用了某个值-如果指针没有引用(因为它为null),它将继续并取消分配引用/对象内存
Main()
{
Test t1;
t1 = new Test();
}