【问题标题】:Does disposing managed objects improve performance in .Net?处置托管对象是否会提高 .Net 中的性能?
【发布时间】:2011-07-08 15:06:22
【问题描述】:

在托管对象上实现 Dispose() 也是如此,这将通过从可能绕过其整个过程的某些提示来提高垃圾收集器的性能。

我在一个没有得到高票的问题上看到了这个answer,但这是真的吗?如果是,那怎么办?

不,那是错误的。我同意 Aaronaught 的观点。 此外,Microsoft 在 2003 年年中 Don Box 的网络广播中建议每个 .Net 开发人员都应该处理自己的对象,无论是托管的还是非托管的,因为这可以将代码性能提高 20%。如果做得好,它可以显着提高性能。因此,这是每个 .net 开发人员都需要了解和使用的核心技能。

【问题讨论】:

    标签: .net garbage-collection


    【解决方案1】:

    您只是不能 Dispose 的托管内存,就像您可以调用 Dispose 来释放文件句柄等一样。唯一可以清理托管内存的是垃圾收集器。

    可以创建一个Dispose 方法,将类中的所有变量设置为null,希望这将允许垃圾收集器更早地收集所有先前引用的对象- 但在极少数情况下它实际上会有所帮助,因为通常您的对象无论如何都会同时符合收集条件。这也会使您的代码更加难以遵循。

    在大多数情况下不必担心对象的生命周期的能力是 C# 的优点之一 - 为什么要通过让每个类都实现 IDisposable 来摆脱它?您真的想自己管理“所有权”和一生吗?

    我怀疑您误读了您在问题中引用的(诚然有些不清楚)答案。我不认为它提倡处置所有对象——我相信它主张明确处置已经实现IDisposable的类型的实例。这与纯托管类型无关,后者几乎从不实现IDisposable

    【讨论】:

    • 是的,我的意思是调用 Dispose 方法并将所有变量/对象引用设置为 null。我将编辑我的问题以反映这一点。您能否详细说明一下它可以提供帮助的几种情况?
    • 我同意我不会在所有课程中使用它。只需要知道它是否有用,在什么情况下有用。
    • @luqi:它几乎从不有用,类设计者很难预测它有用的情况.这使得 all 调用者更难使用,因为他们必须担心生命周期和所有权。只是不要这样做。
    【解决方案2】:

    首先,通过调用 Dispose 方法,它绝不会提示 GC 应该执行任何特殊操作。 Dispose 是一个普通的方法,和其他任何方法一样。

    Dispose 的妙用在于释放不再需要的资源。

    IDisposable 对象的#1 规则是在您使用完它们后调用 Dispose。是的,GC 最终可能会清理内存,但如果这些对象仍然链接到任何其他仍在使用的对象,它们将保留。 Dispose 还会清理非托管资源,这很重要,例如数据库连接、文件句柄、锁等。这些肯定需要尽快关闭。

    简而言之,如果您实例化了一个 IDisposable 对象,请在完成后将其丢弃。

    是的,调用 Dispose 是有代价的,但正如我之前所说,这意味着对象可以相互取消链接,从而允许 GC 在下次运行时释放它们。这也意味着可以立即释放非托管资源。又一次胜利。内存和资源泄漏会严重影响性能,如果过于极端,应用程序也会崩溃!

    开发者可能一直在保护重要资源,所以请不要猜测他!

    分析是您的朋友。如果重新创建这些对象的性能受到关注,请将它们缓存起来,但仍要准备好在完成后将其丢弃。

    【讨论】:

    • 我只对这个问题的托管对象的性能改进感兴趣。
    【解决方案3】:

    正如 Jon Skeet 所指出的,这段代码是糟糕的代码设计:

    public class SomeClass : IDisposable { private string SomeData; public void LoadFileIntoMemory(string filename) { using (var sr = new StreamReader(filename)) { SomeData = sr.ReadToEnd(); } } public void DoSomethingWithDataInMemory() { //whatever } public void Dispose() { SomeData = null; } } class Program { public static void Main() { using (var sC = new SomeClass()) { sC.LoadFileIntoMemory("somefile"); sC.DoSomethingWithDataInMemory(); } } }

    这样做会更好

    public class SomeClass { private string SomeData; public void LoadFileIntoMemory(string filename) { using (var sr = new StreamReader(filename)) { SomeData = sr.ReadToEnd(); } } public void DoSomethingWithDataInMemory() { //whatever } } class Program { public static void Main() { var sC = new SomeClass(); sC.LoadFileIntoMemory("somefile"); sC.DoSomethingWithDataInMemory(); sC = null; } }

    IDisposable 当你的类使用一些资源时应该严格执行,如果类实例的 variable 设置为 null 则不会被清除:)。当您将包含实例设置为 null 时(当 gc 运行时),所有托管资源都将被清除。

    【讨论】:

      【解决方案4】:

      是的,我同意这一点。因为垃圾收集器会在未使用的组件上释放内存,但它会按时执行,如果开发人员自己完成这项工作,这将影响性能,因为额外的对象不会留在内存中,尽管它的内存等待垃圾收集器清理。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-04-13
        • 1970-01-01
        • 2020-07-18
        • 1970-01-01
        • 1970-01-01
        • 2014-01-23
        • 1970-01-01
        相关资源
        最近更新 更多