【问题标题】:What are ways to solve Memory Leaks in C#C#中解决内存泄漏的方法有哪些
【发布时间】:2010-10-15 23:02:50
【问题描述】:

我正在学习 C#。据我所知,您必须正确设置才能让垃圾收集器实际删除所有内容。我正在寻找多年来从你那里学到的智慧,聪明人。

我来自 C++ 背景,非常习惯于代码气味和开发模式。我想了解 C# 中的代码气味。给我建议!

删除内容的最佳方法是什么?

你怎么知道你什么时候有“内存泄漏”?


编辑:我正在尝试制定一个“总是为内存管理做的事情”的清单


非常感谢。

【问题讨论】:

    标签: c# .net memory-leaks garbage-collection


    【解决方案1】:

    C#,.NET Framework 使用托管内存,所有内容(但分配的​​非托管资源)都被垃圾回收。

    假设托管类型总是被垃圾回收是安全的。这包括arraysclassesstructures。随意做int[] stuff = new int[32]; 并忘记它。

    如果您在类中打开文件、数据库连接或任何其他非托管资源,请实现 IDisposable 接口并在您的 Dispose 方法中取消分配非托管资源。

    任何实现 IDisposable 的类都应该被显式关闭,或者在一个(我认为很酷的)Using 块中使用;

    using (StreamReader reader = new StreamReader("myfile.txt"))
    {
       ... your code here
    }
    

    这里 .NET 将在超出 { } 范围时处置阅读器。

    【讨论】:

    • 那个“或”令人困惑——即使是 IDisposable 对象也会被垃圾回收。 GC 对 IDisposable 一无所知。经常 Dispose() 调用 SuppressFinalize,但这无关紧要。
    • 好点。所以包含类被垃圾收集,但它的资源被明确地释放。我从来没想过。
    • “假设托管类型总是被垃圾回收是安全的。”这种说法大错特错。如果仍然可以到达任何内容,则无法进行垃圾收集,程序员必须始终牢记在不再需要时取消他/她的根引用。
    【解决方案2】:

    GC 的第一件事是它是非确定性的;如果您想及时清理资源,请实现IDisposable 并使用using;它不会收集托管内存,但对非托管资源和后续链有很大帮助。

    特别要注意的事项:

    • 大量固定(对 GC 的功能设置了很多限制)
    • 大量终结器(您通常不需要它们;会减慢 GC)
    • 静态事件 - 让大量大型对象图保持活动状态的简单方法;-p
    • 便宜的长寿命对象上的事件,可以看到应该清理的昂贵对象
    • “捕获的变量”意外地使图表保持活动状态

    为了调查内存泄漏...“SOS”是最简单的方法之一;您可以使用 SOS 查找某个类型的所有实例,以及可以看到它的内容等。

    【讨论】:

    • 阿门静态事件是危险的。
    【解决方案3】:

    一般来说,您越少担心 C# 中的内存分配,您的情况就越好。当我遇到收集问题时,我会把它留给分析员告诉我。

    您不能像在 C++ 中那样在 C# 中创建内存泄漏。垃圾收集器将永远“支持你”。您可以做的是创建对象并保存对它们的引用,即使您从不使用它们。这是需要注意的代码异味。

    除此之外:

    • 了解收集的频率(出于性能原因)
    • 对对象的引用不要超过你需要的时间
    • 完成后立即处置实现 IDisposable 的对象(使用 using 语法)
    • 正确实施IDisposable interface

    【讨论】:

      【解决方案4】:

      我能想到的内存泄漏的主要来源是:

      • 保留对不再需要的对象的引用(通常在某种集合中) 所以在这里您需要记住,您添加到集合中的所有内容也将保留在内存中。

      • 具有循环引用,例如让代表注册一个事件。因此,即使您明确地不引用一个对象,它也不能被垃圾回收,因为它的一个方法被注册为一个带有事件的委托。在这些情况下,您需要记住在丢弃引用之前删除委托。

      • 与本机代码互操作并且无法释放它。即使您使用实现终结器的托管包装器,CLR 通常也不会足够快地清理它们,因为它不了解内存占用。您应该使用 using(IDisposable){} 模式

      【讨论】:

      • “循环引用”不是真正的问题 - 问题是这两个项目之一仍然可以被有效地看到,并且事件使第二个对象保持活动状态.
      【解决方案5】:

      内存管理要考虑的另一件事是,如果您正在实现任何观察者模式并且没有正确处理引用。

      例如: 对象 A 监视对象 B 如果从 A 到 B 的引用未释放属性,则对象 B 被释放,GC 将不会正确释放该对象。因为事件处理程序仍被分配,GC 不会将其视为未使用的资源。

      如果您有一小部分正在使用的对象,这可能与我无关。但是,如果您使用数以千计的对象,这可能会导致在应用程序的整个生命周期内内存逐渐增加。

      有一些很棒的内存管理软件应用程序可以监控您的应用程序堆的情况。我发现使用 .Net Memory Profiler 有很大的好处。

      HTH

      【讨论】:

        【解决方案6】:

        我推荐使用 .NET Memory Profiler

        .NET Memory Profiler 是一个强大的工具,用于查找内存泄漏并优化用 C#、VB.NET 或任何其他 .NET 语言编写的程序中的内存使用情况。

        .NET 内存分析器将帮助您:

        • 查看实时内存和资源信息
        • 通过收集和比较 .NET 内存快照轻松识别内存泄漏
        • 查找未正确处理的实例
        • 获取有关非托管资源使用情况的详细信息
        • 优化内存使用
        • 调查生产代码中的内存问题
        • 执行自动内存测试
        • 检索有关本机内存的信息

        看看他们的视频教程:

        http://memprofiler.com/tutorials/

        【讨论】:

          【解决方案7】:

          其他人已经提到了 IDisposable 的重要性,以及代码中需要注意的一些事项。

          我想建议一些额外的资源;在了解 .NET GC 的详细信息以及如何解决 .NET 应用程序中的内存问题时,我发现以下内容非常宝贵。

          CLR via C# Jeffrey Richter 是一本优秀的书。光是 GC 和内存一章就值回票价了。

          这个blog(由 Microsoft“ASP.NET 升级工程师”提供)通常是我使用 WinDbg、SOS 和发现某些类型的内存泄漏的提示和技巧的首选来源。 Tess 甚至设计了 .NET 调试演示/实验室,将引导您了解常见的内存问题以及如何识别和解决这些问题。

          Debugging Tools for Windows(WinDbg、SOS 等)

          【讨论】:

          • Tess 的博客绝对推荐这个话题,是的。
          【解决方案8】:

          您可以使用CLR profiler 之类的工具,学习如何正确使用它需要一些时间,但毕竟它是免费的。 (帮我找了好几次内存泄露)

          【讨论】:

            【解决方案9】:

            确保对象被删除,或者用 .NET 术语进行垃圾回收的最佳方法是确保所有根引用(可以通过方法和对象跟踪到线程调用堆栈上的第一个方法的引用)到一个对象被设置为空。

            如果对象有任何根引用,GC 不能也不会收集对象,无论它是否实现 IDisposable。

            循环引用不会造成任何损失或内存泄漏的可能性,因为 GC 在对象图中标记了它访问过的对象。在委托或事件处理程序的情况下,通常会忘记删除事件中对目标方法的引用,因此如果事件是根的,则无法收集包含目标方法的对象。

            【讨论】:

              【解决方案10】:

              删除内容的最佳方法是什么?

              注意:以下内容仅适用于包含非托管资源的类型。它对纯托管类型没有帮助。

              可能最好的方法是实现并遵循 IDisposable 模式;并在所有实现它的对象上调用 dispose 方法。

              “使用”语句是您最好的朋友。简单地说,它会为你调用实现 IDisposable 的对象的 dispose。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2013-04-01
                • 1970-01-01
                • 1970-01-01
                • 2011-08-14
                • 2019-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多