GVKun编程网logo

在C#中使用Finalize / Dispose方法(c# finalizer)

5

想了解在C#中使用Finalize/Dispose方法的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于c#finalizer的相关问题,此外,我们还将为您介绍关于C#GCFinalizerI

想了解在C#中使用Finalize / Dispose方法的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于c# finalizer的相关问题,此外,我们还将为您介绍关于C# GC Finalizer IDispseable,.Net的垃圾回收机制、c# – Dispose,Finalize,SuppressFinalize方法、c# – IDisposable GC.SuppressFinalize(this)位置、c# – 为Windows phone Silverlight Pages实现Dispose和Finalize的新知识。

本文目录一览:

在C#中使用Finalize / Dispose方法(c# finalizer)

在C#中使用Finalize / Dispose方法(c# finalizer)

C#2008

我已经为此工作了一段时间,但我仍然对在代码中使用finalize和dispose方法感到困惑。我的问题如下:

  1. 我知道在处理非托管资源时我们只需要一个终结器即可。但是,如果存在调用非托管资源的托管资源,是否仍需要实现终结器?

  2. 但是,如果我开发的类不直接或间接使用任何非托管资源,是否应该实现,IDisposable以允许该类的客户端使用“使用语句”?

实现IDisposable只是为了使您的类的客户端能够使用using语句是否可行?

    using(myClass objClass = new myClass()){    // Do stuff here}
  1. 我在下面开发了这个简单的代码来演示Finalize / dispose的使用:
    public class NoGateway : IDisposable

    {
    private WebClient wc = null;

    public NoGateway(){    wc = new WebClient();    wc.DownloadStringCompleted += wc_DownloadStringCompleted;}// Start the Async call to find if NoGateway is true or falsepublic void NoGatewayStatus(){    // Start the Async''s download        // Do other work here    wc.DownloadStringAsync(new Uri(www.xxxx.xxx));}private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e){    // Do work here}// Dispose of the NoGateway objectpublic void Dispose(){    wc.DownloadStringCompleted -= wc_DownloadStringCompleted;    wc.Dispose();    GC.SuppressFinalize(this);}

    }

有关源代码的问题:

  1. 在这里,我没有添加终结器,通常,终结器将由GC调用,而终结器将调用Dispose。由于没有终结器,我什么时候调用Dispose方法?是该类的客户必须调用它吗?

因此,在示例中,我的类称为NoGateway,客户端可以使用和处置此类,如下所示:

    using(NoGateway objNoGateway = new NoGateway()){    // Do stuff here   }

当执行到达using块的末尾时,将自动调用Dispose方法,还是客户端必须手动调用dispose方法?即

    NoGateway objNoGateway = new NoGateway();// Do stuff with objectobjNoGateway.Dispose(); // finished with it
  1. 我使用的是WebClient在我的班级NoGateway课。因为WebClient实现IDisposable接口,这是否意味着WebClient间接使用非托管资源?有严格的规则可以遵循吗?我怎么知道一个类使用非托管资源?

答案1

小编典典

推荐的IDisposable模式在此处。在编写使用IDisposable的类时,通常应使用两种模式:

当实现不使用非托管资源的密封类时,只需像常规接口实现一样实现Dispose方法:

public sealed class A : IDisposable{    public void Dispose()    {        // get rid of managed resources, call Dispose on member variables...    }}

实现未密封的类时,请执行以下操作:

public class B : IDisposable{        public void Dispose()    {        Dispose(true);        GC.SuppressFinalize(this);    }    protected virtual void Dispose(bool disposing)    {        if (disposing)        {            // get rid of managed resources        }           // get rid of unmanaged resources    }    // only if you use unmanaged resources directly in B    //~B()    //{    //    Dispose(false);    //}}

请注意,我尚未在中声明终结器B;仅当您有要处理的实际非托管资源时,才应实现终结器。CLR处理可终结对象与不可终结对象的方式有所不同,即使SuppressFinalize被调用也是如此。

因此,除非必须这样做,否则不应该声明终结器,但是如果类的继承者Dispose直接使用非托管资源,则可以给它们的继承者一个钩子来调用您自己并实现终结器:

public class C : B{    private IntPtr m_Handle;    protected override void Dispose(bool disposing)    {        if (disposing)        {            // get rid of managed resources        }        ReleaseHandle(m_Handle);        base.Dispose(disposing);    }    ~C() {        Dispose(false);    }}

如果您不直接使用非托管资源(SafeHandle并且朋友不声明,因为他们声明了自己的终结器),则不要实现终结器,因为GC处理终结类的方式有所不同,即使您以后取消终结器也是如此。还要注意,即使B没有终结器,它仍然会调用SuppressFinalize以正确处理实现终结器的所有子类。

当一个类实现IDisposable接口时,这意味着当您结束使用该类时,应该删除一些非托管资源。实际资源封装在类中;您无需明确删除它们。只需Dispose()将类调用或包装在中即可using(...){}确保在必要时清除所有不受管理的资源。

C# GC Finalizer IDispseable,.Net的垃圾回收机制

C# GC Finalizer IDispseable,.Net的垃圾回收机制

1.GC只能回收堆里的托管资源

2.GC 回收,"代"的概念

.net 托管资源分三代,代数越大 资源的生命周期越长.

0 代 和1代的资源比较少可以比较频率的回收, 回收2代以上差不多等于对整个应用程序的堆进行遍历了,比较不适合频繁的回收.

GC.Collection() 对所有代的资源进行遍历 回收, GC.collection(1) 则是只回收0代和1代

3.GC回收的过程

对没有被引用的堆资源标记成可回收,对已标记成可回收的资源进行回收,

对于有析构函数的资源判断是否已执行过析构函数,如果没有执行过,对其进行复活.如果有执行过了,标记成可回收,下次GC才回收.

回收完后堆中的资源压缩空间,可以理解成  垃圾箱中的一部份垃圾被灭霸消灭了,把垃圾箱重新踩实,堆中的地址发生了变化,栈,静态引用,CPU寄存器引用的指针更新地址

4.Finalization

在GC回收的过程中讲到析构函数,所以有必要补充的说一下什么是析构函数

publci class MyClass

{

    ~MyClass()

    {
            //在下就是析构函数
    }

}

析构函数的作用是用来释放非托管资源.C++资源 , stream ,ect..但是它只能被GC调用,回收的时机是不确定的.

5 IDispseable 接口

如果只是实现了析构函数,那么回收的时间不能确定,性能相对来说比较差.所以.Net给出另一个答案,IDispseable接口

此接口中只有一个方法 void Dispose();

void Dispose()
{
    //释放非托管资源

GC.SuppressFinalize(this); //GC在回收时将不再调用此类的析构函数 }

用这个方法释放非托管之后还要执行这行代码 .

Dispose和Finalizeter  可以一起使用.MSDN上推荐的实现如下

 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 
 8 namespace MemoryTest.Model
 9 {
10     public class MyClass : IDisposable
11     {
12         #region 变量声明
13         // 指向外部非托管资源
14         private IntPtr handle;
15         // 此类使用的其它托管资源.
16         private Component Components;
17         // 跟踪是否调用.Dispose方法,标识位,控制垃圾收集器的行为
18         private bool isDisposed = false; 
19         #endregion
20 
21         #region Finalizer
22         ~MyClass()
23         {
24             Dispose(false);
25         }
26         #endregion
27 
28         #region IDispseable 接口实现
29         public void Dispose()
30         {
31             Dispose(true);
32             GC.SuppressFinalize(this);
33         }
34         #endregion
35 
36         #region 释放方法
37         /// <summary>
38         /// 释放非托管资源
39         /// </summary>
40         /// <param name="isManual">手动调用为true,系统调用为flase</param>
41         protected virtual void Dispose(bool isManual)
42         {
43             if (isDisposed) return;
44             isDisposed = true;
45             //释放非托管资源
46             handle = IntPtr.Zero;
47 
48             if (isManual)
49             {
50                 //释放其他disose对象
51                 Components?.Dispose();
52             }
53 
54         } 
55         #endregion
56     }
57 }

 

c# – Dispose,Finalize,SuppressFinalize方法

c# – Dispose,Finalize,SuppressFinalize方法

我可以在同一个类中实现这两个方法吗?

public class MyClass : Idisposable
{
  // some implementation
  // if i missed to call dispose() method;
  ~MyClass()
  {
  // it means,clear all does not mananage resources 
  // but dont use dispose() method 
  }
  public void dispose()
  {
   // clear resources
   // if i call this method will i can do this:
   GC.SuppressFinalize()
   // it means dont use Finalizw method for this object
  }
}

我对吗?因为我无法理解这个GC.SuppressFinalize()方法?

解决方法

是的,您可以按照自己的意愿实施这两种方法.

通常,如果对象可以同时具有托管和非托管引用,则正确的模式是:

public class MyClass : Idisposable
{
  ~MyClass()
  {
    dispose(false);
  }
  public void dispose()
  {
    GC.SuppressFinalize(this); 
    dispose(true);
  }
  public virtual void dispose(bool disposing)
  {
    if(disposing)
    {
      // clear MANAGED references
    }
    // free UNMANAGED resources
  }
}

但您可以根据需要实现此功能.这只是一种模式.例如,如果您没有任何非托管资源并且您的类是密封的(因此您可以确定它不会使用任何非托管资源),您可以实现它,就像:

public sealed class MyClass : Idisposable
{
  public void dispose()
  {
    // release managed references
  }
}

忘记终结者了.

在第一个模式中,GC.SuppresFinalize(this)正在做什么,告诉垃圾收集器在释放对象时不应该调用终结器(~MyClass()方法):如果你专门调用了dispose()那么你已经调用了你的虚拟dispose(bool)函数,为什么要再次调用它?

问题是终结器本身在C#中是不确定的:你不知道什么时候会被调用…你甚至不能保证它甚至会被调用(尽管它会在正常清理过程中被调用)如果它之前没有被调用过,这就是Idisposable存在的原因,它是一种确定性地释放托管对象的方式,并释放并释放由它分配的非托管资源.

如果GC释放了一个对象,那么它所拥有的所有托管引用也将被释放,因此在调用终结器时不需要清除托管引用.

但是,您的应用程序应尽最大努力释放和释放它拥有的任何非托管资源.

如果你忘了dispose(),它们应该有最后的机会被释放(当GC收集对象时,或者在应用程序运行时进行最后的清理).在正常模式中你也可以实现一个终结器,如果你之前还没有完成它,请告诉它清理非托管资源

请注意,与流行的看法相反,对dispose()的调用并不特别,它只是一个方法调用:如果需要,可以将其称为FreeMyObject()或FooBar().它不会使垃圾收集器释放任何内存.通过使用Idisposable有一种模式,它非常重要,它可以获得自己的语言语法结构(使用块),但它只是一种模式.您可以执行与dispose()相同的操作,而无需实现Idisposable.

c# – IDisposable GC.SuppressFinalize(this)位置

c# – IDisposable GC.SuppressFinalize(this)位置

我的代码使用默认的Idisposable实现模板(模式).

片段:

public void dispose()
{
    dispose(true);

    GC.SuppressFinalize(this);
}

protected virtual void dispose(bool isdisposing)
{
    if (!this.disposed)
    {
        if (isdisposing)
        {
            //cleanup managed resources
        }

        //cleanup unmanaged resources

        this.disposed = true;
    }
}

我的问题:为什么在dispose public方法中调用“GC.SuppressFinalize(this)”?在处理托管资源后,我将在保护方法的“if(isdisposing)”部分放置“GC.SuppressFinalize(this)”.

喜欢这个:

protected virtual void dispose(bool isdisposing)
{
    if (!this.disposed)
    {
       if (isdisposing)
       {
           //cleanup managed resources

           GC.SuppressFinalize(this);
       }

       //cleanup unmanaged resources

       this.disposed = true;
    }
}

解决方法

我想这是一个明确的模板设计模式.

您的抽象类被设计为处理所需的所有重要/必需的任务(这里,GC.SuppressFinalize(this)),并允许派生类仅覆盖代码的一部分.

这里有两种情况:
代码片段1,SuppressFinalize,处理
Snippet 2,in dispose(true)

这里,Snippet 1,确保始终执行GC.SuppressFinalize.而代码段2,在派生类的支持下执行GC.SuppressFinalize.

因此,通过放置GC.SuppressFinalize,在dispose方法中,您作为类的设计者始终确保无论派生类写入的代码如何,GC.SuppressFinalize都将被执行.

这只是在dispose中编写SuppressFinalize而不是dispose(true)的好处.

c# – 为Windows phone Silverlight Pages实现Dispose和Finalize

c# – 为Windows phone Silverlight Pages实现Dispose和Finalize

我有一个关于图形,弹出窗口和动画的大解决方案.我发现在页面导航期间我有大量内存泄漏.

尝试

因此,我尝试了第一个解决方案:

protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        if (App.RootFrame.CanGoBack)
            App.RootFrame.RemoveBackEntry();
        GC.Collect();
        base.OnNavigatedTo(e);
    }

这来自MSDN和Stackoverflow上的几个来源,应该删除为页面存储的内存.情况并非如此,我不确定代码的MVVM结构是否以某种方式保存信息.然后我尝试实现解构器并在事件被触发时将值强制为null,如:

~SecondScreen()
    {
        In_Game_Crest = null;
        currentviewmodel = null;
    }

这是我为所有页面,弹出窗口和用户控件所做的.然后我再次使用调试来完成代码,并且解析器的页面中没有被解雇.这导致我尝试使用Idisposable和fiddeling与MVVMLight提供的viewmodelLocator,但没有任何成功.

调查

我已阅读以下内容解决此问题:
 StackOverFlow: Finalizer and Dispose

Finalize/Dispose pattern in C#

MSDN: Implementing a Dispose Method

MSDN: Implementing Finalize and Dispose to Clean Up Unmanaged Resources

问题

但它让我感到困惑,而不是帮助了我.我应该如何为我的Windows Phone实现页面的dispose和finalize方法?

由于我正在使用MVVM结构,这些方法应该在viewmodel中实现还是在给定页面后面或两者中实现?

Windows手机的例子将非常感激.

初步尝试使用dispose

我已经阅读了更多有关该主题的内容,并发现最终定型可能不应该写出来?但我仍然不确定.但基于此和上面的第一个MSDN链接,我尝试了以下内容:

private bool disposed = false;

    public void dispose()
    {
        dispose(true);
        // Take yourself off the Finalization queue 
        // to prevent finalization code for this object
        // from executing a second time.
        GC.SuppressFinalize(this);
    }

    protected virtual void dispose(bool disposing)
    {
  // Check to see if dispose has already been called.
  if(!this.disposed)
  {
     // If disposing equals true,dispose all managed 
     // and unmanaged resources.
     if(disposing)
     {
        // dispose managed resources.
         currentView = null;
         popup = null;
         Image1 = null;
         Image2 = null;
     }
          // Release unmanaged resources. If disposing is false,// only the following code is executed.
          this.Content = null;
          // Note that this is not thread safe.
          // Another thread Could start disposing the object
          // after the managed resources are disposed,// but before the disposed flag is set to true.
          // If thread safety is necessary,it must be
          // implemented by the client.

  }
  disposed = true;         
    }

    // Use C# destructor Syntax for finalization code.
    // This destructor will run only if the dispose method 
    // does not get called.
    // It gives your base class the opportunity to finalize.
    // Do not provide destructors in types derived from this class.

    ~FirstPage()
    {
        dispose(false);

    }
    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        this.dispose();
        base.OnNavigatedFrom(e);
    }

但是,但是当我到达第二个屏幕时,这只会让我的记忆增加23MB.这再次引出了我的问题,我应该如何以及应该尝试实施什么,以及为什么内存会增加?

this = null,base.dispose()

我已经看到了不同的实现,在dispose函数中使用this = null或使用base.dispose().我认为后者只能在类是Idisposable时使用?这是要走的路吗?如果是这样我该怎么办呢?

使用Microsoft Profiler

所以我使用分析器来验证FirstPage是否被删除

从上图可以看出第一页存在.在评论中,我被告知要查找实例并参考元素.因此我选择了firstpage的实例并得到了:

这里确认FirstPage永远不会被销毁.但是我被困在这里,我应该如何解释这些数据呢?
希望得到一些帮助.

解决方法

当用户离开页面时实际上不需要处置,再次创建对象的性能影响大于在应用程序处于活动状态期间在内存中具有页面的内存负载.
您应该在从内存中删除对象之间做出决定.再次重新创建同一组对象.
说完这个之后你应该小心导航模型.
如果您在每次用户导航到页面时创建对象而在用户导航时不实际处置,则可能会出现内存问题.
为此,我建议您完全理解应用程序中的PageBase和NavigationHelper或NavigationService类.
你已经提到在应用程序的生命周期内没有从内存中删除FirstPage,根据我的说法是理想的.
将调试点放在代码中可能创建重对象的位置;
导航几次到不同的页面,然后回来.
检查行为,然后您可以自己清楚地了解情况.
对于所有对象,请检查您是否手动调用dispose.
dispose是一个与GarbageCollector完全不同的概念,dispose只是一个开发人员应该遵守的契约,通过调用它来释放他们认为不再需要在内存中维护的资源,因为平台的垃圾收集是在不确定的时间进行的.

在您发布的示例中,我看到您将对象设置为null而未实际处理.设置为null只会更改变量指向的内存位置.
它不会立即破坏对象.一个理想的配置应该如下.

//Call on OnClosing or OnExit or similar context
protected override void dispose(bool isdisposing)
{

        if(isdisposing && !_isdisposed){
         if(disposeableImage != null){
           disposeableImage.dispose();
           disposeableImage = null;
         }
        }
}

关于在C#中使用Finalize / Dispose方法c# finalizer的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于C# GC Finalizer IDispseable,.Net的垃圾回收机制、c# – Dispose,Finalize,SuppressFinalize方法、c# – IDisposable GC.SuppressFinalize(this)位置、c# – 为Windows phone Silverlight Pages实现Dispose和Finalize的相关信息,请在本站寻找。

本文标签: