理解C#垃圾回收机制我们首先说一下CLR(公共语言运行时,Common Language Runtime)它和Java虚拟机一样是一个运行时环境,核心功能包括:内存管理、程序集加载、安全性、异步处理和线程同步。

CTS(Common Type System)通用类型系统,它把.Net中的类型分为2大类,引用类型与值类型。.Net中所有类型都间接或直接派生至System.Object类型。所有的值类型都是System.ValueType的子类,而System.ValueType本身却是引用类型。

托管资源:  

由CLR管理的存在于托管堆上的称为托管资源,注意这里有2个关键点,第一是由CLR管理,第二存在于托管堆上。托管资源的回收工作是不需要人工干预的,CLR会在合适的时候调用GC(垃圾回收器)进行回收。

非托管资源:

非托管资源是不由CLR管理,例如:Image Socket, StreamWriter, Timer, Tooltip, 文件句柄, GDI资源, 数据库连接等等资源(这里仅仅列举出几个常用的)。这些资源GC是不会自动回收的,需要手动释放。

通过上面的讲述总结一下,第一,GC(垃圾回收器)只回收托管资源,不回收非托管资源。第二,GC回收是要在合适的时候(CLR觉得应该进行回收的时候)才进行回收。那么非托管如何进行回收呢?下面就让我一一道来。

在.Net中释放非托管资源主要有2种方式,Dispose,Finalize

Dispose方法,对象要继承IDisposable接口,也就会自动调用Dispose方法。

Class Mhq:System.IDisposable
{
#region IDisposable 成员 public void Dispose()
{
//
} #endregion
}
Mhq mhq= new Mhq(); mhq.Dispose(); //也可以使用Using语句
(using Mhq mhq= new Mhq())
{
//
}

Finalize()方法

MSDN上的定义是允许对象在“垃圾回收”回收之前尝试释放资源并执行其他清理操作。
它的本质就是析构函数

class Car
{
~Car() // destructor
{
// cleanup statements...
}
}

该析构函数隐式地对对象的基类调用 Finalize。 这样,前面的析构函数代码被隐式地转换为以下代码:

protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}

在.NET中应该尽可能的少用析构函数释放资源,MSDN2上有这样一段话:

实现 Finalize 方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。用 Finalize 方法回收对象使用的内存需要至少两次垃圾回收。当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。这时,它不能回收具有终结器的不可访问对象。它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。该列表中的项指向托管堆中准备被调用其终止代码的对象。垃圾回收器为此列表中的对象调用 Finalize 方法,然后,将这些项从列表中移除。后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。在后来的垃圾回收中,实际上回收了对象的内存。

所以有析构函数的对象,需要两次,第一次调用析构函数,第二次删除对象。而且在析构函数中包含大量的释放资源代码,会降低垃圾回收器的工作效率,影响性能。所以对于包含非托管资源的对象,最好及时的调用Dispose()方法来回收资源,而不是依赖垃圾回收器。
在一个包含非托管资源的类中,关于资源释放的标准做法是:

  1. 继承IDisposable接口;
  2. 实现Dispose()方法,在其中释放托管资源和非托管资源,并将对象本身从垃圾回收器中移除(垃圾回收器不在回收此资源);
  3. 实现类析构函数,在其中释放非托管资源。

请看MSDN上的源码

Public class BaseResource:IDisposable
{
PrivateIntPtr handle; // 句柄,属于非托管资源
PrivateComponet comp; // 组件,托管资源
Privateboo isDisposed = false; // 是否已释放资源的标志 PublicBaseResource
{
} //实现接口方法
//由类的使用者,在外部显示调用,释放类资源
Public void Dispose()
{
Dispose(true);// 释放托管和非托管资源 //将对象从垃圾回收器链表中移除,
// 从而在垃圾回收器工作时,只释放托管资源,而不执行此对象的析构函数
GC.SuppressFinalize(this);
} //由垃圾回收器调用,释放非托管资源 ~BaseResource()
{
Dispose(false);// 释放非托管资源
} //参数为true表示释放所有资源,只能由使用者调用
//参数为false表示释放非托管资源,只能由垃圾回收器自动调用
//如果子类有自己的非托管资源,可以重载这个函数,添加自己的非托管资源的释放
//但是要记住,重载此函数必须保证调用基类的版本,以保证基类的资源正常释放
Protectedvirtual void Dispose(bool disposing)
{
If(!this.disposed)// 如果资源未释放 这个判断主要用了防止对象被多次释放
{
If(disposing)
{
Comp.Dispose();// 释放托管资源
} closeHandle(handle);// 释放非托管资源
handle= IntPtr.Zero;
}
this.disposed= true; // 标识此对象已释放
}
}

【C#复习总结】垃圾回收机制(GC)2的更多相关文章

  1. 垃圾回收机制GC知识再总结兼谈如何用好GC

    一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般 ...

  2. 垃圾回收机制GC知识再总结兼谈如何用好GC(转)

    作者:Jeff Wong 出处:http://jeffwongishandsome.cnblogs.com/ 本文版权归作者和博客园共有,欢迎围观转载.转载时请您务必在文章明显位置给出原文链接,谢谢您 ...

  3. 垃圾回收机制GC知识再总结兼谈如何用好GC(其他信息: 内存不足)

    来源 图像操作,易内存泄露,边界像素 一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对 ...

  4. .NET 之 垃圾回收机制GC

    一.GC的必要性 1.应用程序对资源操作,通常简单分为以下几个步骤:为对应的资源分配内存 → 初始化内存 → 使用资源 → 清理资源 → 释放内存. 2.应用程序对资源(内存使用)管理的方式,常见的一 ...

  5. 垃圾回收机制GC

    垃圾回收机制GC 我们已经知道,name = 'leethon'这一赋值变量的操作,是将变量与数据值相绑定. 而数据值是存储到内存中的,有时变量会重新赋值即绑定其他数据值,而使得原本的数据值无法通过变 ...

  6. 【C#复习总结】垃圾回收机制(GC)1

    摘要:今天我们漫谈C#中的垃圾回收机制,本文将从垃圾回收机制的原理讲起,希望对大家有所帮助. GC的前世与今生 虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由 ...

  7. C#垃圾回收机制(GC)

    GC的前世与今生 虽然本文是以.net作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是 ...

  8. java垃圾回收机制GC

    记得第一次总结java 的GC的时候,是刚开始在课堂上学习GC的时候,那时候许老师第一节java课 课后老师说同学们可以去深入理解一下java的GC机制: 但是是花费了三四个小时,翻看了<Thi ...

  9. JVM与垃圾回收机制(GC)和类的生命周期

    JVM运行时数据区 GC(垃圾回收机制) 什么是垃圾回收机制: 在系统运行过程中,会产生一些无用的对象,这些对象占据着一定的内存,如果不对这些对象清理回收无用的是对象,可能会导致内存的耗尽,所以垃圾回 ...

随机推荐

  1. 在线图片上传、预览、裁切、放大、缩小之 cropbox.js 的应用

    cropbox.js 是一个实现了图像在线剪裁的 jQuery .YUI 插件和 JavaScript 库. 上DEMO: 上传的图片可以使用滚轮放大与缩小当前选择的图片,后点击“裁切”后,在右侧的预 ...

  2. Html:html是什麽、html文件结构

    相关内容: html是什麽 html文件结构 首发日期:2018-02-12 html是什么: hmtl超文本标记语言,标准通用标记语言下的一个应用. html专门用于网页,它的“标志符”告诉了浏览器 ...

  3. SAP生产机该不该开放Debuger权限

    前段时间公司定制系统在调用SAP RFC接口的时候报错了,看错误消息一时半会儿也不知道是哪里参数数据错误,就想着进到SAP系统里面对这个接口做远程Debuger,跟踪一下参数变量的变化,结果发现根本就 ...

  4. 惰性求值——lodash源码解读

    前言 lodash受欢迎的一个原因,是其优异的计算性能.而其性能能有这么突出的表现,很大部分就来源于其使用的算法--惰性求值. 本文将讲述lodash源码中,惰性求值的原理和实现. 一.惰性求值的原理 ...

  5. jQuery 实现文字不停闪烁效果

    使用jQuery实现的小效果:文字不停地闪烁. var flag = true; var text= $('#blink').text(); // blink是需要闪烁的元素id function b ...

  6. C#核心基础--类的继承

    继承 一个类可以继承自另一个类.在 C#中,类与类之间只存在单一继承.也就是说,一个类的直接基类只能有一个.当类与类之间实现继承的时候,子类可以将它的直接基类的所有成员当做自己的成员,除了类的静态构造 ...

  7. .svn文件夹特别大

    一个项目通过svn管理,迭代开发一年之后,.svn目录达到20G或更大,对于SSD硬盘来说是非常占用空间的,经过我的尝试,可以使用tortoiseSVN自带的cleanup为文件夹瘦身. 操作方法: ...

  8. cURL模拟POST提交数据

    首先,是这个代码: <?php //curl模拟post提交数据$url = "http://127.0.0.1/immoc/output.php";$post_data = ...

  9. 第六章 第一个Linux驱动程序: 统计单词个数

    一.编写Linux驱动程序的步骤 第1 步:建立Linux 驱动骨架(装载和卸载Linux 驱动) 骨架部分主要是Linux驱动的初始化和退出函数,代码如下: #include <linux/m ...

  10. LeetCode算法题-Same Tree(Java实现)

    这是悦乐书的第162次更新,第164篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第21题(顺位题号是100).给定两个二叉树,编写一个函数来检查它们是否相同.如果两个二 ...