【问题标题】:.NET constructors and memory management question.NET 构造函数和内存管理问题
【发布时间】:2011-05-10 14:48:51
【问题描述】:

来自更底层的语言,如 C++,并看到 .NET 内存管理是多么透明,我就我编写的一行代码举办了一场音乐会。

在 C++ 中,每个对象都必然(指定的设计实践和内存管理的特性)需要有一个构造函数和一个析构函数。在 .NET 中,并不经常需要析构函数,并且在何时需要以及如何使用它们方面存在不同的模式。我的问题是这个。如果我有以下类似的代码(在 VB.NET 中,但同样适用于 C#)

Dim myObj As New MyClass( <some parameters here> )

后面是代码中的以下行

myObj = New MyClass( <some other parameters> )

以上会导致内存泄漏吗?思考这种情况的正确方法是什么?

【问题讨论】:

  • @Cody 我刚刚重新阅读了这个问题并正在编辑它,但是你先到了那里。谢谢=)

标签: c# .net vb.net memory-management constructor


【解决方案1】:

不,这不会导致内存泄漏。你写的代码很好。关于 C#(和其他 .NET 语言),您必须记住的一点是它们是垃圾收集

与 C++ 不同,在 C++ 中,您明确负责自己创建和释放内存,在 .NET 的托管世界中情况并非如此。您只需要担心创建 对象。当不再有对它的任何剩余引用时,它就有资格进行垃圾回收。说真的,考虑到您的其他语言背景,我知道这听起来很奇怪,但您真的应该让垃圾收集器担心这些事情。 “思考这种情况的正确方法”确实是根本不去想它们!

事实上,只有你需要编写析构函数(因此担心内存管理)是你的类使用非托管对象(如窗口句柄、GDI+ 对象等) .) 或其他需要显式关闭的对象(文件句柄、数据库连接等)。在 .NET 世界中,您希望尽可能很少编写析构函数,因为这样做会带来轻微的性能损失。细节在于垃圾收集算法的实现,以及在什么时候可以收集对象,但你不应该试图学习所有这些。

要记住的重要一点是,如果您确实需要在对象被销毁时“清理”,您应该实现 IDisposable interface,就像许多使用非托管对象的 WinForms 类(例如 Control)一样内部。

这里有一些很好的资源可以帮助你了解更多关于 .NET 的垃圾收集模型:

【讨论】:

    【解决方案2】:

    .NET 中的对象被垃圾回收。你不需要删除它们。

    一些保持非托管状态的对象(例如通过 P/Invoke 从 C 函数分配的对象),例如 System.IO.Stream,将实现终结器和 IDisposable。您可以通过两种方式使用它们:

    Stream s = ...
    ...
    s.Dispose();
    

    或者更安全的方法:

    using(Stream s = ...)
    {
        ...
    } // Dispose is called automatically
    

    即使您不调用 Dispose,这些对象最终也会被垃圾回收,但无法保证何时会发生这种情况,因此这样做通常是个好主意。

    您自己的任何具有一次性成员的类也应该实现 IDisposable 以清理它们。

    【讨论】:

      【解决方案3】:

      不会造成内存泄漏。 垃圾收集器会回收之前的对象。

      所有托管资源使用的内存将由垃圾收集器处理。

      【讨论】:

        【解决方案4】:

        否定的。 CLR 使用引用计数器维护对所有实例的引用;每隔一段时间,内存垃圾收集器就会运行并找到没有任何代码引用的所有引用,它会释放该内存。

        在你的情况下,它只是意味着在未来的某个时候,由于你不再引用 MyClass 的原始实例,垃圾收集器会为你释放它的内存。这是正常操作;所以你不必担心! =D

        【讨论】:

        • .Net 的 GC 中没有引用计数。它遍历各种根(线程堆栈、全局变量等)以查找引用的对象。
        • @Yuck:Mono 和 Microsoft 的 GC 实现都没有使用引用计数。这就是为什么它在面对循环引用时仍然有效。
        • 是的,VB 6 和 COM 使用引用计数,但它们没有对 .NET 的 CLR 使用相同的算法。如果您好奇的话,我的答案中的链接提供了很多关于内部结构的血腥细节。
        • 我发誓我在 MS 的设计指南书中读到了这一点。现在我将不得不返回并重新阅读该部分。
        • @Yuck:您的困惑可能是由于“引用计数”作为垃圾收集算法与确定不再有任何对对象的引用不同,因此它是有资格进行垃圾收集。 CLR 的垃圾回收实现使用引用计数;相反,它会遍历堆栈并检查无法访问的对象(即不再引用的对象)。两者都使用了“参考”一词,但后者不同于参考 counting 作为一种算法,后者保持文字数字计数。
        猜你喜欢
        • 2021-12-06
        • 1970-01-01
        • 1970-01-01
        • 2011-03-22
        • 2011-09-14
        • 2011-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多