【问题标题】:Some best practice questions about C# Unmanaged object Disposing关于 C# 非托管对象处理的一些最佳实践问题
【发布时间】:2015-02-19 04:38:56
【问题描述】:

我正在开发单声道和 .net 应用程序。我有一些关于最佳做法的基本问题。

  1. 如果我需要创建一个非托管对象只使用一次(可能传递给一个方法或调用其中一个方法)并且以后不需要它,我应该先将它分配给一个变量然后使用它以便我可以处理它(或者可以在using() 块中分配变量)或者我应该像new Class().Method() 一样使用,以便 GC 能够收集它?最佳做法是什么?

  2. 我是否需要处置仅具有方法的局部范围的对象,或者如果我处置属于类(全局)属性的对象就足够了吗?

  3. 我有一个 A 类和一个 B 类。B 的一个对象是在 A 类的某个方法 M 中创建的。这个(B 类的)对象有另一个方法 M2,它调用 A 类中的第二个方法 M3。所以结构如下

    Class A
    {
      void M()
      {
       var b = new B();
       }
      public string M3()
      {
        return "OK";
       }
      }
      Class B
      {
        void M2()
        {
         Console.WriteLine(new A().M3();
         }
       }
    

这会创建一个循环引用并阻止 GC 收集这两个对象吗?

良好的内存效率编程的其他一般原则是什么?

【问题讨论】:

  • 这是所有托管代码。您真正需要参与内存管理和对象处理的几乎唯一一次是使用非托管资源(使用IDisposableusing 以节省许多麻烦,或者在每次使用时交替尝试/最终确保调用dispose)或者您正在管理资源连接,例如数据库连接或流(最有可能实现 IDisposable,因此放置得当的 using 也可以将您保存在那里)。

标签: c# .net memory-management mono garbage-collection


【解决方案1】:

这个问题很可能会变得“过于宽泛”,即与 StackOverflow 无关。也就是说,一些简要答案:

  1. 如果我需要创建一个非托管对象只是为了使用一次(可能传递给一个方法或调用其中一个方法)并且以后不需要它......最佳做法是什么?

使用任何非托管对象的最佳实践是将其包装在SafeHandle 的实例中。当然,您必须处理的最常见的非托管对象已经被 .NET 包装,或者在 IDisposable 的某些自定义实现中(例如 StreamReader),或者在较新的框架代码中,作为 SafeHandle 子类。

但是当您处理自己的 .NET 不知道的非托管对象时,您需要遵循 .NET 的示例并使用 SafeHandle

  1. 我是否需要处理仅具有方法的局部范围的对象,或者如果我处理属于类(全局)属性的对象就足够了?

如果您创建了对象,并且没有将其传递给其他代码以供其拥有,并且您不打算从方法中返回它,那么您需要处置它。您确实需要处理仅在方法中引用的对象。

通常您会使用using 语句来执行此操作。

  1. …这会创建一个循环引用并阻止 GC 收集这两个对象吗?

暂时忽略您的代码示例无法编译,也不包含任何引用循环...... :)

与某些内存管理方案(例如引用计数)不同,.NET 的垃圾收集完全没有循环引用的任何问题。根据是否可以从 root 引用访问对象来确定对象是否可收集。两个相互引用的无根对象仍然不能从根引用到达,因此都是可收集的。

良好的内存效率编程的其他一般原则是什么?

这对于 StackOverflow 来说绝对是太宽泛了。即使在 .NET 使用的基于 GC 的系统中,也有很多可以关注的细节。基本系统消除了许多常见的编程错误,但它有自己的特殊行为,在某些情况下理解这些行为很重要。

花一些时间浏览有关该主题的 MSDN 和 Web 文章将帮助您了解更多关于 .NET 和一般垃圾收集的信息。如果您有其他具体问题,请随时在 StackOverflow 上发布。

【讨论】:

  • 这几乎回答了我所有的问题。我想我需要重新构建我的第一个问题。这有点误导我真正想问的问题。我的场景是我只需要一行代码的非托管对象的范围。我可以像 new ClassName().Method() 或 (var obj = new ClassName(){obj.method;} 一样使用它 我的问题是第一个选项是创建一个对象并保留在对象图中还是不是这样没有被分配给变量?如果没有,那不是更好的做法吗?否则它应该分配一个我们无法处理的内存?
  • @Sreeraj:我不确定你的意思;您的示例似乎没有非托管对象。但忽略这一点,答案是:没关系。无论哪种方式,都会分配一个对象。无论哪种方式,GC 都会在看到您不再使用它时将其删除。变量无关紧要; GC 甚至可以收集一个对象,即使它在理论上被例如引用。一个局部变量,只要 JIT 编译器优化器发现该对象实际上从未在某个点之后被引用。
  • @Sreeraj:(续...)当然,如果您编写像ClassName 实现IDisposable 的代码并且您不处置该对象,那就是一个错误。除非您将值保存在变量中,否则您将无法处置该对象,最好将其声明为using 语句的一部分。但目前尚不清楚这是否是您问题的一部分。该示例似乎没有涉及IDisposable
  • 评论的第二部分完美地回答了我的问题。谢谢你 。我想知道这种风格是否会分配一些内存,因为它没有分配给变量。现在我明白了。我应该将所有非托管对象分配给一个变量,以便它们可以被释放
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多