`
cloudtech
  • 浏览: 4605403 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

理解C#垃圾回收机制

 
阅读更多

很多系统都有其自身的垃圾回收,其回收机制大体是相同的。它们使程序员从跟踪内存使用的繁重任务中解脱出来。虽然大多数回收器都要求应用程序不时地暂停从而释放不再使用的内存。但C#中的回收器效率还是很高的。
垃圾回收器的基本假定:
1.被分配内存空间的对象最有可能被释放。在方法执行时,就需要为该方法的对象分配内存空间,搜索最近分配的对象集合有助于花费最少的代价来尽可能多地释放内存空间。
2.生命期最长的对象释放的可能性最小,经过几轮垃圾回收后,对象仍然存在,搜索它时就需要进行大量的工作,却只能释放很小的一部分空间。
3.同时被分配内存的对象通常是同时使用,将它们彼此相连有助于提高缓存性能和回收效率 。
C#中的回收器是分代的垃圾回收器(Gererational Garbage Collector) 它将分配的对象分为3个类别或代。(可用GC.GetGeneration方法返回任意作为参数的对象当前所处的代) 最近被分配内存的对象被放置于第0代,因为第0代很小,小到足以放进处理器的二级(L2)缓存,所以它能够提供对对象 的快速存取。经过一轮垃圾回收后,仍然保留在第0代中的对象被移进第1代中,再经过一轮垃圾内存回收后,仍然保留在第1代中的对象则被移进第2代中,第2代中包含了生存期较长的对象。
在C#中值类型是在堆栈中分配内存,它们有自身的生命周期,所以不用对它们进行管理,会自动分配和释放。而引用类型是在堆中分配内存的。所以它的分配和释放就需要像回收机制来管理。C#为一个对象分配内存时,托管堆可以立即返回新对象所需的内存,因为托管堆类似于简单的字节数组,有一个指向第一个可用内存空间的指针,指针像游标一样向后移动,一段段内存就分配给了正在运行的程序的对象。在不需要太多垃圾回收的程序小,托管堆性能优于传统的堆。
当第0代中没有可以分配的有效内存时,就触发了第0代中的一轮垃圾回收,它将删除那些不再被引用的对象,并将当前正在使用的对象移至第1代。而当第0代垃圾回收后依然不能请求到充足的内存时,就启动第1代垃圾回收。如果对各代都进行了垃圾回收后仍没有可用的内存就会引发一个OutOfMemoryException异常。

终结器
在有些情况下,类可以提供一个终结器在对象被销毁时执行,终结器是一个名为Finalize的受保护的方法:

protectedvoidFinalize()
{
base.Finalize();
//释放外部资源
}

垃圾回收器使用名为“终止队列”的内部结构跟踪具有Finalize方法的对象。每次您的应用程序创建具有Finalize方法的对象时,垃圾回收器都在终止队列中放置一个指向该对象的项。托管堆中所有需要在垃圾回收器回收其内存之前调用它们的终止代码的对象都在终止队列中含有项。(实现Finalize方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。用Finalize方法回收对象使用的内存需要至少两次垃圾回收。当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。这时,它不能回收具有终结器的不可访问对象。它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。该列表中的项指向托管堆中准备被调用其终止代码的对象。垃圾回收器为此列表中的对象调用Finalize方法,然后,将这些项从列表中移除。后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。在后来的垃圾回收中,实际上回收了对象的内存。)
Dispose方法
在不使用终结器时,可以考虑使用Dispose方法,你可以使用这个方法来释放所保存包括的在托管对象引用在内的任何资源。但使用它时需用GC.SuppressFinalize来告知运行时这些对象不需要终结。如下所示:

publicvoidDispose()
{
object.Dispose();
dbConnection.Dispose();
GC.SuppressFinalize(this);//申明不需要终结
}

创建并使用了Dispose方法的对象,就需要使用完该对象之后调用这些方法,最好是在Finally中调用。


1//以下代码演示来自MSDN
2//Designpatternforthebaseclass.
3//ByimplementingIDisposable,youareannouncingthatinstances
4//ofthistypeallocatescarceresources.
5publicclassBaseResource:IDisposable
6{
7//Pointertoanexternalunmanagedresource.
8privateIntPtrhandle;
9//Othermanagedresourcethisclassuses.
10privateComponentComponents;
11//TrackwhetherDisposehasbeencalled.
12privatebooldisposed=false;
13
14//ConstructorfortheBaseResourceobject.
15publicBaseResource()
16{
17//Insertappropriateconstructorcodehere.
18}

19
20//ImplementIDisposable.
21//Donotmakethismethodvirtual.
22//Aderivedclassshouldnotbeabletooverridethismethod.
23publicvoidDispose()
24{
25Dispose(true);
26//TakeyourselfofftheFinalizationqueue
27//topreventfinalizationcodeforthisobject
28//fromexecutingasecondtime.
29GC.SuppressFinalize(this);
30}

31
32//Dispose(booldisposing)executesintwodistinctscenarios.
33//Ifdisposingequalstrue,themethodhasbeencalleddirectly
34//orindirectlybyauser'scode.Managedandunmanagedresources
35//canbedisposed.
36//Ifdisposingequalsfalse,themethodhasbeencalledbythe
37//runtimefrominsidethefinalizerandyoushouldnotreference
38//otherobjects.Onlyunmanagedresourcescanbedisposed.
39protectedvirtualvoidDispose(booldisposing)
40{
41//ChecktoseeifDisposehasalreadybeencalled.
42if(!this.disposed)
43{
44//Ifdisposingequalstrue,disposeallmanaged
45//andunmanagedresources.
46if(disposing)
47{
48//Disposemanagedresources.
49Components.Dispose();
50}

51//Releaseunmanagedresources.Ifdisposingisfalse,
52//onlythefollowingcodeisexecuted.
53CloseHandle(handle);
54handle=IntPtr.Zero;
55//Notethatthisisnotthreadsafe.
56//Anotherthreadcouldstartdisposingtheobject
57//afterthemanagedresourcesaredisposed,
58//butbeforethedisposedflagissettotrue.
59//Ifthreadsafetyisnecessary,itmustbe
60//implementedbytheclient.
61
62}

63disposed=true;
64}

65
66//UseC#destructorsyntaxforfinalizationcode.
67//ThisdestructorwillrunonlyiftheDisposemethod
68//doesnotgetcalled.
69//Itgivesyourbaseclasstheopportunitytofinalize.
70//Donotprovidedestructorsintypesderivedfromthisclass.
71~BaseResource()
72{
73//Donotre-createDisposeclean-upcodehere.
74//CallingDispose(false)isoptimalintermsof
75//readabilityandmaintainability.
76Dispose(false);
77}

78
79//AllowyourDisposemethodtobecalledmultipletimes,
80//butthrowanexceptioniftheobjecthasbeendisposed.
81//Wheneveryoudosomethingwiththisclass,
82//checktoseeifithasbeendisposed.
83publicvoidDoSomething()
84{
85if(this.disposed)
86{
87thrownewObjectDisposedException();
88}

89}

90}

91
92//Designpatternforaderivedclass.
93//Notethatthisderivedclassinherentlyimplementsthe
94//IDisposableinterfacebecauseitisimplementedinthebaseclass.
95publicclassMyResourceWrapper:BaseResource
96{
97//Amanagedresourcethatyouaddinthisderivedclass.
98privateManagedResourceaddedManaged;
99//Anativeunmanagedresourcethatyouaddinthisderivedclass.
100privateNativeResourceaddedNative;
101privatebooldisposed=false;
102
103//Constructorforthisobject.
104publicMyResourceWrapper()
105{
106//Insertappropriateconstructorcodehere.
107}

108
109protectedoverridevoidDispose(booldisposing)
110{
111if(!this.disposed)
112{
113try
114{
115if(disposing)
116{
117//Releasethemanagedresourcesyouaddedin
118//thisderivedclasshere.
119addedManaged.Dispose();
120}

121//Releasethenativeunmanagedresourcesyouadded
122//inthisderivedclasshere.
123CloseHandle(addedNative);
124this.disposed=true;
125}

126finally
127{
128//CallDisposeonyourbaseclass.
129base.Dispose(disposing);
130}

131}

132}

133}

134
135//ThisderivedclassdoesnothaveaFinalizemethod
136//oraDisposemethodwithoutparametersbecauseitinherits
137//themfromthebaseclass.
138

System.GC类
GC类包含了可使用户与垃圾回收机制进行互操作的静态方法,包括发起新一轮垃圾回收操作的方法。确定某对象当前所在代的方法及当前分配内存空间的方法。
GC.Collect(); //无参时将发起一轮全面的回收。
GC.Collect(i);//(0<=i<=2)对第i代进行垃圾回收。
GetTotalMemory将返因分配于托管堆上的内存空间总量。当参数为True时,在计算之前将进行一轮全面的垃圾回收。如下所示:

longtotalMemory=System.GC.GetTotalMemory(True);

下面是在.NET Framework 2.0 版中是新增的公共方法:
通知运行库在安排垃圾回收时应考虑分配大量的非托管内

publicstaticvoidAddMemoryPressure(longbytesAllocated)//bytesAllocated
已分配的非托管内存的增量。

返回已经对对象的指定代进行的垃圾回收次数。

publicstaticintCollectionCount(
intgeneration
)

通知运行库已释放非托管内存,在安排垃圾回收时不需要再考虑它。

publicstaticvoidRemoveMemoryPressure(
longbytesAllocated
)

分享到:
评论

相关推荐

    c#的GC垃圾回收机制详细讲解文档

    首先:谈谈托管,什么叫托管,我的理解就是托付C#运行环境帮我们去管理,在这个运行环境中可以帮助我们开辟内存和释放内存,开辟内存一般用new,内存是随机分配的,释放主要靠的是GC也就是垃圾回收机制。哪么有两个...

    浅谈关于C#的垃圾回收机制

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

    c#如何用好垃圾回收机制GC

    主要介绍了c# 如何用好垃圾回收机制GC,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下

    PHP5.3的垃圾回收机制(动态存储分配方案)深入理解

    在现在的流行各种语言当中,垃圾回收机制是新一代语言所共有的特征,如Python、PHP、Eiffel、C#、Ruby等都使用了垃圾回收机制。 虽然垃圾回收是现在比较流行的做法,但是它的年纪已经不小了。早在20世纪60年代MIT...

    C#开发常见问题清单总结与入门常见问题.docx

    技巧8:利用C#垃圾回收机制减少内存泄漏风险 技巧9:使用IDisposable接口与using语句管理非托管资源 4. 并发与多线程编程 技巧10:线程同步与并发控制 技巧11:避免死锁的策略与设计模式 技巧12:线程安全编程与锁...

    C#5.0本质论第四版(因文件较大传的是百度网盘地址)

    9.7.3 垃圾回收、终结和IDisposable 284 9.8 推迟初始化 286 9.9 小结 288 第10章 异常处理 289 10.1 多异常类型 289 10.2 捕捉异常 291 10.3 常规catch块 293 10.4 异常处理的规范 295 ...

    编程课程+C#基础课程+C#&.NET技术开发+基础系列课程

    - 性能优化技巧:探索异步编程、内存管理和垃圾回收机制,提高应用程序的性能和响应能力。 - 微服务架构实践:了解微服务架构的理念,学习如何设计和实现微服务系统。 - 实战项目开发:从需求分析到部署维护,全程...

    C#.Net的常见面试试题

    C#.Net的常见面试试题 &lt;br/&gt; 1.面向对象的思想主要包括什么? &lt;br/&gt;2.什么是ASP.net中的用户控件 &lt;br/&gt;3....如何理解.net中的垃圾回收机制。 &lt;br/&gt;20.常用的调用webservice方法有哪些?

    CLR.via.C#.(中文第3版)(自制详细书签)

    · 理解垃圾回收器是如何管理内存资源的 · 使用线程池、任务、取消、计时器和异步I/O操作来设计响应性强、稳定性高和伸缩性大的解决方案 · 借助于异常处理来进行状态管理 · 使用CLR寄宿、AppDomain、程序集...

    C#微软培训资料

    14.1 C#的继承机制.155 &lt;&lt;page 3&gt;&gt; page begin==================== 14.2 多 态 性 .159 14.3 抽象与密封 .163 14.4 继承中关于属性的一些问题.169 14.5 小 结 .172 第四部分 深入了解 C#.174 第十...

    CLR.via.C#.(中文第3版)(自制详细书签)Part2

    · 理解垃圾回收器是如何管理内存资源的 · 使用线程池、任务、取消、计时器和异步I/O操作来设计响应性强、稳定性高和伸缩性大的解决方案 · 借助于异常处理来进行状态管理 · 使用CLR寄宿、AppDomain、程序集加载、...

    C#实训教程

    1.7 垃圾回收 9 1.8 链接 10 1.9 实例分析 11 1.10 内容总结 13 1.11 独立实践 14 2 C#基础 15 2.1 面向对象基本概念 15 2.2 变量 18 2.3 常量 22 2.4 预定义数据类型 22 2.5 流控制 28 2.6 数组 37 2.7 命名空间 38...

    C#栈和堆的区别浅谈

    垃圾回收的机制使程序员从复杂的内存管理中解脱出来,虽然绝大多数的C#程序并不需要程序员手动管理内存,但这并不代表程序员就无需了解分配的对象是如何被回收的,在一些特殊的场合仍需要程序员手动进行内存管理。...

    C++中的单例模式及按需释放模型

    甚至是有垃圾回收机制的C#上也是这样的,系统切换了功能模块还存在大量的这个模块根本不使用的单例类对象,实际上是很浪费存储空间的,单例类少还好说,如果单例类有几十甚至几百的时候(中大型项目这个数量不算夸张...

    CLR.via.C#.(中文第3版)(自制详细书签)Part1

    · 理解垃圾回收器是如何管理内存资源的 · 使用线程池、任务、取消、计时器和异步I/O操作来设计响应性强、稳定性高和伸缩性大的解决方案 · 借助于异常处理来进行状态管理 · 使用CLR寄宿、AppDomain、程序集加载、...

    CLR.via.C#.(中文第3版)(自制详细书签)Part3

    · 理解垃圾回收器是如何管理内存资源的 · 使用线程池、任务、取消、计时器和异步I/O操作来设计响应性强、稳定性高和伸缩性大的解决方案 · 借助于异常处理来进行状态管理 · 使用CLR寄宿、AppDomain、程序集加载、...

    C#深入理解堆栈、堆在内存中的实现

    尽管在.NETframework下我们并不需要担心内存管理和垃圾回收(GarbageCollection),但是我们还是应该了解它们,以优化我们的应用程序。同时,还需要具备一些基础的内存管理工作机制的知识,这样能够有助于解释我们日常...

    asp.net面试题

    不定项选择题(共14题,单选或多选): ... A.scriptB.bodyC.titleD.link 二、下面哪段javascript能弹出一个提示框?...19.如何理解.net中的垃圾回收机制。 答:GC?对象创建了总要清除啊,不然内存哪够用?

    疯狂JAVA讲义

    1.7 垃圾回收机制 20 1.8 何时开始使用IDE工具 21 学生提问:老师,我想学习Java编程,到底是学习Eclipse好呢,还是学习JBuilder好呢? 21 1.9 本章小结 22 本章练习 22 第2章 理解面向对象 23 2.1 面向对象 ...

    net学习笔记及其他代码应用

    24.在C#中,string str = null 与 string str = “” 请尽量使用文字或图象说明其中的区别。 答:string str = null 是不给他分配内存空间,而string str = \"\" 给它分配长度为空字符串的内存空间。 25.请详述在...

Global site tag (gtag.js) - Google Analytics