C# ~ 由 IDisposable 到 GC

IDisposable 接口

托管资源和非托管能源

  • 托管财富
    • CL奇骏 控制和管制的内部存储器财富,如程序中在 Heap
      上分红的靶子、成效域内的变量等;
    • GC
      机制完毕活动内存管理和托管堆的全权管理;
  • 非托管财富
    • CL汉兰达无法说了算管理的片段,如文件流Stream/数据库连接coonection/窗口句柄/组件COM等;
    • Finalize 方法(析构函数) GC
      隐式自动调用,Dispose
      方法手动强制显式调用;
    • 尽量制止使用 Finalize() 方法清理财富,推荐完毕 Dispose()
      方法供显式调用;

注:MSDN – 完成 Finalize()
方法或析构函数对品质恐怕会有负面影响。用 Finalize()
方法回收对象占用的内部存款和储蓄器至少要求一次垃圾回收,第一回调用析构函数,第二遍删除对象。
GC 机制在回收托管对象内部存款和储蓄器在此以前,会先调用对象的析构函数。   

析构函数(Finalize方法)
.vs. Dispose方法

Finalize 方法用于释放非托管财富,Dispose
方法用于清理或自由由类占用的非托管和托管财富。IDisposable
接口定义见上,自定义类应落到实处 IDisposable 接口,设计标准:

  • 能够重新调用 Dispose() 方法;
  • 析构函数应该调用 Dispose() 方法;
  • Dispose() 方法应该调用 GC.SuppressFinalize()
    方法,提示垃圾回收器不再重复回收该对象;

在二个分包非托管财富的类中,财富清理和刑释的正经方式是:

  1. 继承 IDisposable 接口;
  2. 兑现 Dispose()
    方法,在内部释放托管和非托管财富,并将指标从垃圾堆回收器链表中移除;
  3. 兑现类的析构函数,在里头释放非托管能源;

当中,变量 “isDisposing”
来分别手动显式调用(true)照旧GC隐式调用(false)。

  public class MyDispose : IDisposable
  {
      public MyDispose() { }
      ~MyDispose() { 
          Dispose(false); 
      }

      private bool isDisposed = false;
      public void Dispose(){
          Dispose(true);
          System.GC.SuppressFinalize(this);
      }        
      protected virtual void Dispose(bool isDisposing)  // 子类可重写
      {
          if (false == this.isDisposed)
          {
              if (true == isDisposing){
                  OtherManagedObject.Dispose();      // 释放托管资源 ...
              }
              OtherUnManagedObjectDisposeOrClose();  // 释放非托管资源 ...             
              this.isDisposed = true;
          }         
      }
  }

析构函数执行在类的实例被销毁从前供给的清理或释放非托管财富的行为,注意不能够在析构函数中自由托管财富。类的析构函数被编写翻译后自动生成
protected void Finalize() 方法,GC
垃圾回收时会调用该措施并对继承链中的全数实例递归地调用 Finalize() 方法。

Object.Finalize() 方法不可重写。

  • 类的析构函数不足持续和重载、无法带访问修饰符,三个类至多有多个析构函数;
  • 析构函数只针对类的实例对象,未有静态析构函数;

    protected void Finalize(){

     try{
         // 
     }
     finally{
         base.Finalize();
     }
    

    }

Finalize() 方法被调用的地方:

  • 显式调用System.GC 的 Collect方法(不建议);
  • Windows 内部存款和储蓄器不足、第G0代对象充满;
  • 应用程序被关闭或 CL凯雷德 被关闭;

Dispose() 方法的调用分 二 种:

  • 选取 using 语句会自行调用:using( MyDispose myObj = new MyDispose()
    ) {…}
  • 显式调用:myObj.Dispose();

一个能源安全的类,都应促成 IDisposable
接口和析构函数,提供手动释放能源和系统自动释放财富的双管教。(壹)若一个类A有1个兑现了
IDisposable
接口类型的积极分子并创办(创造而不是收纳,必须是由类A创设)它的实例对象,则类A也理应达成IDisposable 接口并在 Dispose 方法中调用全数达成了 IDisposable
接口的积极分子的 Dispose 方法;(二)纵然基类完成了 IDisposable
接口,那么其派生类也要实现 IDisposable 接口,并在其 Dispose
方法中调用基类中 Dispose 方法;唯有如此才能担保拥有达成了 IDisposable
接口的类的对象的 Dispose 方法能被调用到、手动释放其余必要释放的能源。

参考

何以 IEnumerator 接口未有继续 IDisposable
接口

托管能源和非托管财富
IDisposable接口的二个一级例子
Finalize – Dispose –
SuppressFinalize

IDisposable和Finalize的分别和联系
对.Net 垃圾回收 Finalize 和 Dispose
的通晓

深入精晓 C#
中能源自由

GC 垃圾回收

实质:跟踪全数被引用到的靶子,整理不再被引述的对象并回收相应内部存款和储蓄器。

优点

  • 减弱由于内部存款和储蓄器运用不当发生的Bug,降低编制程序复杂度;
  • 登时的内存管理;
  • 增加软件系统的内聚;


Generation

NET 垃圾回收器将 CLXC90托管堆内的靶子分为叁代:G0、G壹、G贰,代龄机制辅助有选用地查询,进步垃圾回收质量,幸免回收整个托管堆。

  • G0:小指标(Size<8四千Byte),近来被分配内部存款和储蓄器的对象,支持快捷存取对象;
  • G一:在GC中存活下来的G0对象,CLRubicon 检查过叁遍未被回收的G0对象;
  • G二:大目的(Size>=八四千Byte),CLOdyssey检查过一回及以上仍未被回收的G1/G二对象;

通过 GC.GetGeneration()
方法能够回来对象所处的代。当第0代对象已满时,自动进行垃圾回收,第0代中未被放飞的靶子变成第3代,新创制的对象变成第0代,以此类推,当第0代再度充满时会再次实施垃圾回收,未被保释的靶子被添加到第一代。随着程序的施行,第3代对象会生出垃圾,此时废品回收器并不会立刻施行回收操作,而是等第叁代被浸透回收并整治内部存款和储蓄器,第贰代中未被释放的对象变成第1代。当第二代收集时,第0代也亟需收集,当第1代收集时,第贰和第0代也急需收集。


root

每种应用程序都带有壹组根,各种根都以三个存储地方,包蕴一个指南针或引用托管堆上的八个对象或为null,由
JIT编写翻译器 和 CL大切诺基运维时 维护根(指针)列表。

干活规律

基于代的排放物回收器如下即使:

  • 对象越新,生存期越短,近日分配内部存款和储蓄器空间的指标最有一点都不小恐怕被保释,搜索近来抽成的对象集合有助于花费最少的代价来尽量多地放出内部存款和储蓄器空间;
  • 指标越老,生存期越长,被保释的恐怕性越小,经过几轮GC后,对象如故存在,搜索代价大、释放内部存款和储蓄器空间小;
  • 程序的区域性原理
    :同时分配的内部存款和储蓄器对象平常还要采用,将它们互相相连有助于增长缓存品质和回收成效;
  • 回收堆的1有的速度快于回收整个堆;

标记和化解 (马克 & Sweep)
收集算法:防止出现 “环引用” 造成内部存储器败露
利用内部结构的 终止队列(Finalization Queue) 跟踪保存具有 Finalize
方法(定义了析构函数)的指标。

  • ReRegisterForFinalize():将指标的指针重新添加到Finalization队列中;(允许系统推行Finalize方法)
  • SuppressFinalize():将对象的指针从Finalization
    队列中移除;(拒绝系统推行Finalize方法)

先后制造具有 Finalize
方法的对象时,垃圾回收器会在终止队列中添加二个对准该指标的项(引用或指针)。当目的不可达时,未有定义析构函数的不可达对象直接由
GC 回收,定义了析构函数的不可达对象从终止队列中移除到
终止化-可达队列(F-reachable
Queue)中。在二个特有的专用线程上,垃圾回收器会依次调用该队列中目的的
Finalize
方法并将其从队列中移除,执行后该目的和未有Finalize方法的废物对象壹样,然后在下1次GC 中被回收。(GC线程 和 Finalizer线程 分歧)
算法分 2 步:

  • 标志阶段:垃圾识别。从应用程序的 root
    出发,利用互相引用关系,递归标记(DFS),存活对象被标记,维护一张树图:”根-对象可达图”; 
  • 压缩阶段:内部存储器回收。利用
    Compact
    压缩算法,移动内部存款和储蓄器中的水保对象(大指标除了)并修改根中的指针,使内部存款和储蓄器三番五次、化解内部存款和储蓄器碎片难点,有利于增强内存再一次分配的快慢和高速缓存的性子;  

参考

C#基础知识梳理连串101:垃圾回收机制
步步为营 C# 技术漫谈
4、垃圾回收机制(GC)

污源回收机制 –
Generation的原理分析

详解 Finalization队列与
F-reachable队列

通俗精通 GC
机制

垃圾堆回收GC:.Net自动内部存款和储蓄器管理系列

内部存款和储蓄器泄漏

依照编写翻译原理,内部存储器分配策略有叁种:

  • 静态存款和储蓄区(方法区):编写翻译时即分配好,程序整个运营期间都存在,首要存放在静态数据、全局static数据和常量
  • 栈区:局地变量,自动释放
  • 堆区:malloc或new的动态分配区,需手动释放

推介使用 .Net 内部存储器分析工具:CLR
Profiler
,用来察看托管堆内部存款和储蓄器分配和研商垃圾回收行为的壹种工具。

附注:

该处提供多个狂降内部存款和储蓄器的秘诀(摘自网上),能够小幅优化程序内部存储器占用。
本条函数是将顺序的物理内部存款和储蓄器尽只怕转换为虚拟内存,大大扩大硬盘读写,是倒霉的,慎用!!
使用方法:在程序使得一个计时器,每隔几分钟调用一遍该函数,打开职务管理器

    [DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
    public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
    /// <summary>    
    /// 释放内存    
    /// </summary>    
    public static void ClearMemory()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
        if (Environment.OSVersion.Platform == PlatformID.Win32NT)
        {
            SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
        }
    }

  

 

相关文章