代码之家  ›  专栏  ›  技术社区  ›  Daniel LeCheminant

你如何摆脱C语言中的一个物体?#

  •  6
  • Daniel LeCheminant  · 技术社区  · 17 年前

    在下面的C代码中,当对象不再有用时,如何摆脱它?它是自动处理的,还是我需要做些什么?

    public void Test()
    {
       object MyObject = new object();
    
       ... code ...
    }
    
    7 回复  |  直到 17 年前
        1
  •  5
  •   Jon Skeet    17 年前

    简短的回答是:除非它有非托管的资源(文件句柄等),否则您不必担心。

    长话短说更为复杂。

    当.NET决定释放一些内存时,它会运行 垃圾收集器 . 这将查找所有仍在使用中的对象,并将其标记为这样。任何局部变量(在任何线程的任何堆栈帧中)仍然可以作为 静态变量也是如此。(事实上,我相信静态变量是通过活动类型对象引用的,这些对象是通过活动AppDomain对象引用的,但在大多数情况下,您可以将静态变量视为根。)

    垃圾收集器查看根引用的每个对象,然后根据这些对象中的实例变量找到更多“活动”引用。它反复出现,发现和标记越来越多的物体为“活的”。一旦完成了这个过程,它就可以看到 休息 并释放它们。

    这是一个非常广泛的概念图-但当你想到 代际的 垃圾收集模型、终结器、并发收集等。我强烈建议您阅读Jeff Richter的 CLR via C# 这涉及到很多细节。他也有一个 two part 文章(从2000年开始,但仍然很相关)如果你不想买这本书。

    当然,所有这些并不意味着您不必担心.NET中的内存使用和对象生命周期。特别地:

    • 无意义地创建对象 成本效益。特别是,垃圾收集器速度很快,但不是免费的。寻找 简单的 在编码时减少内存使用的方法,但是在知道有问题之前进行微优化也是不好的。
    • 通过使对象的可访问时间比您预期的长,可以“泄漏”内存。造成这种情况的两个合理常见原因是静态变量和事件订阅。(事件订阅使事件处理程序可以从事件发布服务器访问,但不能从另一个方向访问。)
    • 如果您使用的内存(以一种实时的、可访问的方式)超过了可用内存,您的应用程序将崩溃。没有太多的.NET可以阻止这种情况发生!
    • 使用非内存资源的对象通常实现 IDisposable . 你应该打电话 Dispose 在对象完成后释放这些资源。注意这个 释放对象本身-只有垃圾收集器可以这样做。这个 using C中的语句是最方便的调用方式 处置 可靠的,即使面对例外。
        2
  •  18
  •   JacquesB    17 年前

    自动地。当myObject超出范围时(在测试结束时),它会被标记为垃圾收集。在将来的某个时候,.NET运行时将为您清理内存。

    编辑: (为了完整起见,我应该指出,如果您将myObject传递到某个地方,它将通过引用传递,并且不会被垃圾收集-只有当不再有对该对象的引用在周围浮动时,gc才可以自由地收集它)

    编辑:在一个发布版本中,myObject通常在未使用时就被收集(有关更多详细信息,请参阅我的答案--dp)

        3
  •  4
  •   ChrisW    17 年前

    其他答案是正确的,除非您的对象是实现 IDisposable 接口,在这种情况下,您应该(通过 using 语句)调用对象的 Dispose 方法。

        4
  •  3
  •   Greg Hewgill    17 年前

    在优化的代码中,可能并且可能会在方法结束之前收集myObject。默认情况下,Visual Studio中的调试配置将在打开调试开关和关闭优化开关的情况下生成,这意味着MyObject将保持在方法的末尾(以便在调试时查看该值)。使用optimize off进行构建(在本例中调试并不重要),可以在确定myObject未使用后收集它。强制它在方法末尾保持活动状态的一种方法是在方法末尾调用gc.keepalive(myObject)。

        5
  •  2
  •   kthakore    17 年前

    这将强制垃圾收集器除去未使用的对象。

    GC.Collect();
    GC.WaitForPendingFinalizers();
    

    如果希望收集特定对象。

    object A = new Object();
    ...
    A = null;
    GC.collect();
    GC.WaitForPendingFinalizers();
    
        6
  •  1
  •   yfeldblum    17 年前

    它会自动处理。

        7
  •  1
  •   Jim Petkus    17 年前

    通常,垃圾收集可以依赖于清理,但如果对象包含任何非托管资源(数据库连接、打开的文件等),则需要显式关闭这些资源和/或超出对象上的Dispose方法(如果它实现IDisposable)。这可能导致错误,因此您需要小心处理这些类型的对象。在使用完文件后简单地关闭它并不总是足够的,因为在执行close之前的异常会使文件保持打开状态。使用using块或try finally块。

    底线:“使用”是你的朋友。