内存管理对将对象设置为 null 的影响 最后

本文关键字:null 影响 最后 设置 管理 对象 内存 | 更新日期: 2023-09-27 18:25:53

public void func1()
{    
    object obj= null;
    try
    {
             obj=new object();
    }
    finally
    {
             obj = null;
    }
}

在大型对象的内存管理方面,将 null 分配给 finally 块中的引用有什么好处吗?

内存管理对将对象设置为 null 的影响 最后

让我们在这里处理显式和隐性问题。

问:首先,当您完成局部变量时,将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参数从未在方法内部使用,因此即使该方法当前正在运行,也会收集方法周围的对象。