内存管理对将对象设置为 null 的影响 最后
本文关键字:null 影响 最后 设置 管理 对象 内存 | 更新日期: 2023-09-27 18:25:53
public void func1()
{
object obj= null;
try
{
obj=new object();
}
finally
{
obj = null;
}
}
在大型对象的内存管理方面,将 null 分配给 finally 块中的引用有什么好处吗?
让我们在这里处理显式和隐性问题。
问:首先,当您完成局部变量时,将null
分配给它有什么意义吗?
答:没有,完全没有。使用优化进行编译且不在调试器下运行时,JITter 知道正在使用变量的代码段,并在传递该段后自动停止将其视为根。换句话说,如果您将某些内容分配给变量,然后在某个时候再也不从中读取,即使您没有将其显式设置为 null
,也可能会被收集。
因此,您的示例可以安全地编写为:
public void func1()
{
object obj = new object();
// implied more code here
}
如果"此处隐含更多代码"中没有任何代码访问obj
变量,则不再将其视为根。
请注意,如果在未优化的程序集中运行,或者将调试器挂接到进程,则此情况会更改。在这种情况下,变量的作用域被人为地扩展,直到其作用域结束,以便于调试。
问:其次,周围班级的田野呢?
答:在这里,它绝对可以有所作为。
如果方法周围的对象长时间保持活动状态,并且对字段内容的需求已经消失,那么是的,将字段设置为 null
将使其引用的旧对象有资格收集。
因此,此代码可能具有以下优点:
public class SomeClass
{
private object obj;
public void func1()
{
try
{
obj=new object();
// implied more code here
}
finally
{
obj = null;
}
}
}
但是,你为什么要这样做呢?相反,您应该努力编写不依赖于周围状态的更干净的代码。在上面的代码中,您应该重构要在要使用的对象中传递的"此处隐含的更多代码",并删除全局字段。
显然,如果您不能做到这一点,那么是的,一旦不再需要其对象引用,将字段设置为null
是一个好主意。
有趣的实验,如果您在 LINQPad 中运行以下代码并进行了优化,您希望输出是什么?
void Main()
{
var s = new Scary();
s.Test();
}
public class Scary
{
public Scary()
{
Console.WriteLine(".ctor");
}
~Scary()
{
Console.WriteLine("finalizer");
}
public void Test()
{
Console.WriteLine("starting test");
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine("ending test");
}
}
答案(鼠标悬停以显示您认为您已经得到它(:
<块引用类> .ctor
开始测试
终结器
结束测试
解释:
<块引用类> 由于实例方法的隐式this
参数从未在方法内部使用,因此即使该方法当前正在运行,也会收集方法周围的对象。