【问题标题】:Calling dispose within list.removeAll在 list.removeAll 中调用 dispose
【发布时间】:2013-01-09 06:53:34
【问题描述】:

我对 C# 编程还很陌生,GC 的概念及其对 IDisposable 的定义仍然有点模糊。就垃圾收集而言,调用 Dispose 意味着什么? 具体来说,我想知道以下代码是否会偶尔失败,具体取决于垃圾收集何时启动。(我无法在测试期间使其崩溃)。

//List<TestClass2> tc2List;
//TestClass2 invokes a thread. It implements IDisposable. 
//Its Dispose() sets a stop-condition for the thread,
//and joins the thread, awaiting it to stop. (may take 100 msek)

tc2List.RemoveAll(t =>
{
  if (String.Compare(t.Name, "Orange") == 0)
  {
    t.Dispose(); //May take up to 100 msek
    return true;
  }
  return false;
});

【问题讨论】:

  • 如果您是编程新手,请忽略垃圾收集器。他会自动做正确的事情。对包含非托管资源(如 Connections)的对象使用 using,否则不要显式调用 dispose。
  • IDisposable 仅在有 unmanaged(即不是内存;例如考虑 OS 文件句柄)资源在使用时才相关。 IDisposable 的对象通常与 GC 交互,因为它们安排在其内存被回收后自动处置,以作为安全措施,但就连接而言。 GC 和 IDisposable 在其他方面无关。
  • 我的帖子中没有提到这一点,但是该类将保留一个串行端口,直到线程停止。我需要确保它已发布。
  • @Jon:“IDisposable 仅在存在非托管(即非内存;例如考虑 OS 文件句柄)资源在使用时才相关。” - 不是真的。例如,当您在关闭表单时取消事件处理程序时,这一点也很重要。如果您不取消挂钩事件处理程序,您可能会发生内存泄漏。一个合理的解决方案是在这些情况下使用 IDisposable,即使您正在释放的“资源”不是非托管的。例如见stackoverflow.com/questions/452281/…(也见msdn.microsoft.com/en-us/library/aa970850.aspx
  • @MatthewWatson:当然,但这不是技术手册。这是一个专门针对完全新手的简短宣传。我相信你明白了。

标签: c# garbage-collection dispose removeall


【解决方案1】:

我想知道下面的代码是否会偶尔失败,这取决于垃圾收集何时启动

不,它不会失败

//Its Dispose() sets a stop-condition for the thread,
//and joins the thread, awaiting it to stop. (may take 100 msek)

这是一个稍微不典型的 Dispose() 用法,但没有错。更有效的方法是使用不同的Stop(),以便您可以一次停止所有线程。或从Parallel.ForEach() 致电Dispose()。但无论你选择什么方法,它都不会阻碍,也不会被 GC 阻碍。

【讨论】:

    【解决方案2】:

    就垃圾回收而言,调用 Dispose 意味着什么?

    调用 dispose 意味着您正在使用 Dispose 方法的实现强制清理事物(字面意思是内存)。注意:(某些框架类确实会为您调用 Dispose 的实现。例如 System.Windows.Forms.Form)

    对比中的垃圾收集是 .NET 运行时的一项功能,它会自动为您清理内容。我的意思是自动,因为它取决于内存压力和运行时处理的其他因素。

    我会推荐一个简单的策略。如果您认为内存会比需要的时间更长并且会影响应用程序,请执行 Dispose()。否则将其留给运行时,它会在对象超出范围时自动清理(即最终确定)对象。 GC 有自己的清理算法,但您可以在更大程度上依赖它。

    下一个问题 具体来说,我想知道以下代码是否偶尔会失败,具体取决于垃圾收集何时开始

    我猜没有。由于 GC 启动而导致代码失败,取决于您如何编写 TestClass2 的终结器。绝对您的调用 t.Dispose() 不会与 GC 冲突。

    【讨论】:

    • 清理东西(字面意思是内存) - 不,Dispose 根本不会清理/释放/收集内存。
    • Dispose 在语义上假设是这样做的,如果我理解正确的话。
    • Dispose 旨在仅清理非托管资源(如关闭处理程序、清理非托管内存等)。没有托管内存清理。所以说 Dispose 清理内存是非常错误的
    【解决方案3】:

    您的代码有效,但它的风格很糟糕。谓词不应该有副作用。所以你应该先处理元素,然后删除它们。

    Predicate<T> filter = t => t.Name == "Orange";
    foreach(var t in tc2List.Where(filter))
      t.Dispose();
    tc2List.RemoveAll(filter);
    

    【讨论】:

    • 谢谢。我会记住这一点。谓词是 C# 的另一个概念,对我来说是新的 :)
    • t.Name 不会在 t.Dispose() 之后未定义吗?
    • @mhu 取决于你处理对象时它的作用,但你是对的,之后使用它可能不是一个好主意。
    【解决方案4】:

    TestClass2 中有 finalize 方法吗?

    释放主要属性

    1. 这必须在实现 IDispose 接口的类中实现。
    2. 这是释放非托管资源(如文件、句柄和连接等)的正确位置。
    3. Dispose() 方法在代码本身中被显式调用。
    4. Dispose() 方法在“使用”中使用时会自动调用(对于实现 IDispose 的对象)

    请参阅link

    【讨论】:

    • 没有。我的 TestClass 中没有 finalize 方法。根据 Henk Holterman 的评论,我意识到我也不需要 Dispose。我实现了一个 Stop() 来停止我正在使用的线程。
    • 没错,您可能想通过链接(在我的回答中)查看如何以及为什么应该使用 dispose。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    • 1970-01-01
    • 2018-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多