Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 调用Dispose()函数后未释放的对象_C#_Dispose - Fatal编程技术网

C# 调用Dispose()函数后未释放的对象

C# 调用Dispose()函数后未释放的对象,c#,dispose,C#,Dispose,我对处理一件物品有疑问。情况如下 在一个用C开发的桌面应用程序中,我有一个函数,其中一个对象是这样创建的 namespace Class 1 { variables section; .... .... Function1() { local variables; try { Object1 obj = new Object1(); ....

我对处理一件物品有疑问。情况如下

在一个用C开发的桌面应用程序中,我有一个函数,其中一个对象是这样创建的

namespace Class 1
{
    variables section;
    ....
    ....

    Function1()
    {
         local variables;
         try
         {
              Object1 obj = new Object1();
              ....
              ....
              if(true)
              {
                  ....
              }
              else
              {
                   **obj.Dispose();**
              }
          }
          catch()
          {}
          finally
          {}
     }
}
当执行else部分时,对象不会被释放。此的msdn链接是

根据这一点,组件应该重新分配它使用的所有资源

我想知道,为什么不处理该对象

多谢各位


帕万·纳瓦利

首先执行的是else部分吗?你说if部分总是真的

不看你的代码,很难说清楚,但是你可能会把“处置”误认为是一个不同的概念,比如C++中的析构函数或删除/Field/P>>P>,因为你的自定义对象看起来是从System.ComponentModel.Component继承的,您将需要重写Disposebool以处置对象的资源。尽管您的对象继承自具有Dispose方法的System.ComponentModel.Component,但您的对象的自定义资源将不会被处置,除非您将Dispose方法编码为这样做。从System.ComponentModel.Component继承并不是自动得到的。将仅处理System.ComponentModel.Component基类已知的资源

在你的课堂上尝试这样做:

protected override void Dispose(bool disposing)
{
    // release your resources here
}
我们不知道您的对象上有哪些资源没有被释放,但无论对象是什么,都必须对dispose方法进行编码,以便它释放资源。如果未在dispose方法中处置对象的资源,则在处置该资源时不会处置该资源

例如:

ExpensiveResource myExpensiveResource1;
ExpensiveResource myExpensiveResource2;

void Dispose()
{
    // release the resources
    myExpensiveResource1.Dispose();

    // since there is no call to dispose of myExpensiveResource2, it is not disposed of
}

您应该重构代码,使其如下所示:

Function1()
{
  local variables;
  try
  {
     using (Object1 obj = new Object1())
     {
       ....
       ....
       if(true)
       {
         ....
       }
     }
  }
  catch() // I hope you don't use try-catch like this in real code
  {}      // I hope you don't use try-catch like this in real code
  finally // I hope you don't use try-catch like this in real code
  {}      // I hope you don't use try-catch like this in real code
}
using语句确保在obj离开作用域时始终调用它的Dispose。

IDisposable.Dispose只是一个类可以选择实现的方法。该方法的内容完全由类的设计器决定。为了准确地理解出了什么问题,在处理/终结对象时,有许多术语需要理解

处置 Disposing对象意味着只调用对象的Dispose方法。按照惯例,对象会从此函数中释放其非托管资源文件、网络句柄和流。如果在调用Dispose后保留对该对象的引用,则该对象仍将基本正常工作,除非您尝试访问Dispose方法中释放的资源

定稿 当.NET CLR终结器确定没有其他对象使用此特定对象,并且该对象占用的内存现在可以回收时,对象将被终结。程序员无法直接控制强制运行时声明对象死机。您可以强制运行垃圾回收器,但即使这样,也不建议这样做,即您确实需要知道自己在做什么才能涉足GC

我如何知道Dispose已运行? 最好的方法是在Dispose方法中设置断点。如果您没有源代码,可以使用

我可以通过看到进程消耗的内存下降来判断Dispose是否已运行吗? 否。在Dispose运行后,CLR对象仍然存在。对象完成后,内存将释放到托管内存池。如果您确切知道它是什么类型的资源,您可以使用第三方操作系统工具,例如,查看进程是否释放了文件句柄。即使如此,在释放句柄的进程和认为它已被释放的操作系统之间可能存在延迟

我如何知道该对象已最终确定? 同样,通过在终结器中设置断点或运行内存分析器。即使在终结器运行时,实际上很可能内存没有释放到操作系统。它保留在托管内存池中,CLR运行时可以选择稍后使用它

即使如此,当内存被释放到操作系统时,这个过程看起来就像是在使用那个内存。当操作系统感觉需要内存时,它将决定是否使用该内存

如果你试图通过在Process Manager中查看应用程序所消耗的内存量来了解应用程序正在做什么,我可以保证你在尝试分析时会发疯。事实上,试图做到这一点与尝试使用等同。

结论 这些都不能真正回答你的问题。所以,这里有一个清单来解决您的问题,因为我们没有太多的事情要做:

你怎么知道Dispose没有运行?您是否调试了应用程序并在此行设置了断点:*obj.Dispose;**? 如果断点被击中,您是否仔细检查了代码以了解发生了什么? 你能澄清你所说的“未处理的对象”是什么意思吗?
您将处置的概念与垃圾收集的概念混为一谈,在.NET中,处置意味着方法的实现,从而保证释放非托管资源, 它由运行时处理,意味着释放分配给对象的内存。当您维护对任何对象的引用时,垃圾收集器不会触及它——因此,在发生这种情况之前,对象分配的内存不会被释放

这些概念很容易混淆,原因有二:

首先,通过语句处理IDisposable对象通常是一种很好的做法,如下所示:

using (IDisposable d = new MyDisposableObject ()) {
    // do whatever you need d for
}
确保在退出使用块时处理d;但它也将d的作用域限制在块上,这意味着一旦执行存在块,对象也可以自由地进行垃圾收集,而不一定是立即进行垃圾收集,但这既不在这里也不在它们的范围内,因为您的代码不再维护对它的引用。因此,在这个极为常见且可能被视为标准的习语中,处理与删除引用同时发生

其次,对于直接访问非托管资源的类,最好的做法是实现一个调用Dispose的终结器。终结器在对象被垃圾收集时运行,因此您可以确保不会在非托管资源上留下悬空泄漏,但如果对象从未被正确处置,则您将严格由运行时决定何时释放非托管资源,它仅根据内存压力决定何时执行垃圾收集,对非托管资源引用的数量或类型不了解也不感兴趣。因此,在本例中,对象的垃圾收集强制处置非托管资源

在显式调用方法上的Dispose的情况下,例如在您的问题中,假设Object1实现了IDisposable,您仍然保持对obj的引用,因此可以访问其所有属性和方法。当然,这些方法或属性需要您已经处理过的非托管资源是完全合理的,在这种情况下,可能会抛出System.ObjectDisposedException,或者Object1的作者选择处理这种情况,但是,如果它们不需要您释放的资源,它们也完全可以按预期运行


例如,请查看System.IO.FileStream。一旦您处理了它,像ReadByte这样的操作就会抛出一个异常,因为显然没有从中读取文件的权限,但是调用属性CanRead只会返回false,这是有效的和预期的。例如,MemoryStream甚至可以在Dispose调用后访问数据,因为当前的实现使用运行时管理的缓冲区,而不是内核句柄。

对象的类型是什么,您如何知道它没有被释放?您对正在被释放的对象的理解是什么?你怎么知道它没有被处理?你希望它消失吗?除了其他注释之外——如果你的代码是这样的,那么else部分永远不会执行。您能给我们展示一个更好的代码示例吗?在执行else部分时,您是如何检查对象是否未被处置的?您为Dispose编写的代码是否正确?你能把它贴出来吗?其他部分将被执行。重写if条件,如下所示。。。。ifsomecondition{}。。。。我还发布了一篇msdn文章的链接,其中有一个问题,对Dispose函数的描述是释放组件使用的所有资源。将执行else部分。重写if条件,如下所示。。。。ifsomecondition{}。。。。我已经调试了代码,并在obj.Dispose行上的断点被命中后逐步完成了代码。下面的代码是受保护的override void Dispose bool disposing{if disposing{ifcomponents!=null{components.Dispose;}}base.Dispose disposing;}通过未disposed的对象执行的,我的意思是我仍然可以像这样访问对象。。。。ifSomeCondition{}else{obj.Dispose;}string s=obj.Fname//Fname是对象obj的成员…–这是意料之中的行为。一旦没有对象持有对已处置对象的引用,它就会消失。在.NET中,您不必担心这些事情。