dotnet学习笔记四 - 无用单元回收

原创 2003年07月15日 11:42:00

我们平常写程序很少自己去写资源管理的,除非写非常大型的应用程序,或者大公司自己的sdk。看到过PGP源代码的一定知道,PGPSDK就实现了自己的内存管理。自己管理内存烦恼实在多多,忘记释放了,释放了又再次访问的bug层出不穷,这种bug又非常难查。普通的逻辑bug,简单测试发现程序没有按照预想的运行就可以找到。但是内存的问题却很难发现。过去很多公司也为解决这方面的问题作过很大努力,比如CompuwareBoundsCheckerRationalPurify。这些工具使用起来也很困难,经常找到的点都是你用的开发库的代码。现在.NET提供了全套的资源管理(无用资源回收:Garbage Collection,简称GC),能够让我们从中解脱出来,把精力用在自己应该解决的业务问题上去。当然它不是万能的,我们最好多了解他的原理,以便我们可以更好的享用它。

系统资源不是无限的,内存用完要释放,文件,网络连接都是系统资源,用完之后也要释放。在面向对象的系统中,所有的东西都是对象,所以使用任何资源都要从系统分配内存,最后释放它。使用资源的过程无外乎五个步骤:

1.         为代表资源的类型分配内存;

2.         初始化资源状态,请求非内存系统资源(如打开文件,建立网络连接等);

3.         通过访问类型的实例(对象)及其成员变量、方法等来访问资源;(可能多次)

4.         清空资源状态,释放系统资源(如关闭文件,关闭网络连接等);

5.         释放内存

我们遇到的内存问题一般都在上面的五个步骤中,.NET提供的无用单元回收(GC)机制基本上都可以解决这些问题。不过GC是不知道如何清空资源状态和释放系统资源的(即上面的第四步),这就要利用到Fina<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />lize方法,这个我们后面讨论。当然,大部分对象,如字符串等是无需这第四步的。

CLR实现了一个托管堆(Managed Heap),要求所有的资源都必须从这个堆中分配,并且无需释放。下面就详细说明对象是如何在堆中分配,GC又是如何做无用单元回收的。

CLR在进程初始化时,保留一块连续的内存,这块连续的内存就是托管堆。CLR同时为托管堆维护一个指针,这个指针永远指向下一个可以分配的内存空间,我们这里叫NextObjPtr

当程序适用new创建一个对象时,new首先确认堆中是否有足够的内存空间,如果有的话,则为对象分配空间,调用对象的构造函数,返回分配空间的地址,接着NextObjPtr指向剩余空间的地址,即下一个可以分配的地址。如下图:

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />CSDN_Dev_Image_2003-7-151114460.jpg

图中虚线是NextObjPtr的起始地址,分配对象C成功并返回地址后,NextObjPtr移到实线的位置。

再让我们看看普通应用程序的堆内存分配方式。普通的内存分配方式维护一个空闲内存列表,系统首先遍历空闲空间列表,找到一个足够大的空间,然后将其拆分出足够的空间分配,然后再将剩下的空间加入到空闲空间列表。在历史上有很多的实现进程堆内存分配的算法,比如比较著名的二分法等等。但是比较来看,.NET的内存分配方法要快的多。

不过内存不是无限的,堆的空间分配光了怎么办?CLR在分配内存的时候,如果发现堆中的空闲空间不足时,就会启动无用空间回收。GC将堆中不再被使用的对象占用的内存释放掉,然后将堆整理,使其剩下连续的空间以待分配,当然如果没有可以释放的对象或者释放后内存还是不够的话,就抛出OutOfMemoryException异常。GC是如何断定一个对象不再被使用了呢?

每一个应用都有一组根,这些根包括了标示托管堆中一组对象的存储单元。被认为是根的对象包括:

1.         所有的全局和静态对象;

2.         一个线成栈中的局部对象和函数的参数;

3.         任何CPU寄存器包含的指针指向的对象;

上面根的列表由JITCLR维护并且GC可以访问。

开始无用单元回收后GC就开始遍历根,找到第一个根指向的对象,沿着这个对象向下找,找到这个对象所有引用的对象,以及引用之引用,并将其放入到一个集合中。这一个完成后,就接着找下一个根。一旦GC发现某个对象已经在集合中,就停止这个分支的搜寻以防止重复和引用死循环。

完成后,GC就有了一个所有根可以访问到的对象的集合,这个集合中没有的对象就认为是无用的。如下图:

CSDN_Dev_Image_2003-7-151114462.jpg

GC的集合包括了对象ABDF,而对象CEG就是无用对象,GC将释放其资源。GC接着遍历堆中的所有对象,释放无用对象,并将有用对象向内存的地位移动(据说使用的memcpy),以保证空闲空间的连续性。NextObjPtr就被指向空闲空间的开始地址。这样做会使一些对象的引用地址失效,GC负责更正这些指针。回收后的堆如下图:

CSDN_Dev_Image_2003-7-151114464.jpg

这一次回收所作的工作不可谓不复杂,消耗的CPU时间也是很多。不过还好,它不是时时刻刻都在运行,而是只在堆满了之后才回收(实际上是Generation 0满了之后,Generation我将在接下来的文章讨论),其他分配内存的时候还是非常快的。而且.NET提供丰富的设置来提高无用单元回收的效率。

我将在下一节讨论FinalizationGeneration,强引用,弱引用。

dotnet学习笔记四 - 无用单元回收

  • zgqtxwd
  • zgqtxwd
  • 2008年04月24日 15:29
  • 91

dotnet学习笔记六 - 无用资源回收之三

这篇文章接着上一次的来,继续讨论无用资源回收的其它一些话题。l         WeakReference(弱引用)我们平常用的都是对象的强引用,如果有强引用存在,GC是不会回收对象的。我们能不能同时...
  • kenli
  • kenli
  • 2003年07月24日 15:57
  • 1684

dotnet学习笔记五 - 无用资源回收之二

  • zgqtxwd
  • zgqtxwd
  • 2008年04月24日 11:48
  • 136

第四章 OPP 中的初始化和无用单元收集

什么是初始化!● `int main() {int i; int j=10; i=20;}`说明: 根据C++/C 中的定义, i中的值是未定义的, 该值就是创建在 i 的内存区域中所...
  • qq_34536551
  • qq_34536551
  • 2017年07月13日 12:23
  • 174

c++实现无用产生式的消除

 过程you/*    the program is for algorithm of “编译原理 无关文法的消除 ” by-Li    */    #include    #inclu...
  • nightsword
  • nightsword
  • 2014年11月21日 15:51
  • 364

Java垃圾回收(一)对象存活状态判断---深入理解Java虚拟机

程序计数器,虚拟机栈和本地方法栈 首先我们先来看下垃圾回收中不会管理到的内存区域,在Java虚拟机的运行时数据区我们可以看到,程序计数器,虚拟机栈,本地方法栈这三个地方是比较...
  • JokerKon
  • JokerKon
  • 2016年07月25日 23:00
  • 1742

Unity3D基础篇----Shader学习笔记(4)

这一篇,我们来继续学习Shader中纹理的添加以及实现纹理中凹凸的映射。
  • qq_30501909
  • qq_30501909
  • 2017年06月28日 21:56
  • 265

Oracle学习笔记(四)——上机练习一

1、define命令可以用于定义哪种变量 a、number b、char c、varchar2 d、date 【b】 Host变量主要作用是起到一个替代变量的作用,是主机环境可以和...
  • shangqing1123
  • shangqing1123
  • 2016年04月06日 20:55
  • 609

Oracle学习笔记(4)------------简单查询

学习Oracle感觉有点吃力,于是到网上找了一些学习线路,来有规律的学习,效率能高一些,分享给大家 Concepts                        |                 ...
  • u011225629
  • u011225629
  • 2015年05月26日 12:37
  • 1187

Shader学习笔记4

前两篇写的大多是表面着色器(SurfaceShader),有官方的,网上的,自己写的。自己看着都乱,当做仓库用吧。。。 然后就研究到了顶点和片段着色器,发现很自由,功能很多,但是不能处理光照。还有屏...
  • zzw8866755
  • zzw8866755
  • 2016年09月29日 20:02
  • 158
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:dotnet学习笔记四 - 无用单元回收
举报原因:
原因补充:

(最多只允许输入30个字)