对象生命周期

 

好久没有写随笔了,一年了,时间好长,不知道这一年都干什么去了,变的这么懒惰,我不再说什么计划,什么一定要坚持下去的誓言,如果今年还是迷茫的话,就turn right了。

 

了解对象生命周期前,要先理解类、对象与引用是怎么回事。

类:是定义在代码文件中,保存在硬盘上 ,是对象的蓝本,它描述了对象在内存中大概是什么样子的。

对象: 我们都知道.net将值类型存储在栈中,引用类型存储在堆中,这样做的原因是栈中的数据是轻量级的,而堆中的数据是重量级,目的是在应用程序在操作它们的时候比较方便存取,从而提高程序的运行速度。创建一个对象实例,用new+类名+(),就创建了一个对象实例,创建的这个对象实例是引用类型,被存储在托管堆中,以后就不用管它了,new关键字返回一个对象实例存在的地址,这个存储地址(引用)变量,被放在栈中,实际上应用程序在运行时都是操作的这个引用。

引用:上面说了,就是指 堆数据在堆中的地址 存储在栈上。

不知道这样说能说清楚不!

 

下面进入题,说下对象的生命周期:

在传统的非托管C++中,用构造函数创建对象实例,清除内存中的对象实例用析构函数,也就是必须要程序员手写消灭对象实例的方法,这样做的话,如果析构函数执行失败,或是由于程序员的疏忽,忘记了析构代码,那么该对象所占有的内存会一直存在内存中(直到应用程序结束),那么这样很容易造成内存资源的浪费,有效的内存空间得不到充分的利用,从而造成内存泄露。那么在.net框架中,这样的情况将不再存在,.net中不用程序显示回收内存,自带的垃圾收集器会帮我们解决这一困扰,那么垃圾收集器是如何工作的呢?

还是先说下创建对象实例时的内存管理:实际上内存分配存在一个内存指针,它总是指向下一个对象应该放置位置,即当创建一个对象实例,看内存指针在哪里,就将这个对象实例放在指针指向的位置,然后指针再移动到下一个可以存放对象的地址,等待下一个对象的到来。

创建一个对象实例要经过三步:

1.         计算新的对象实例要用多少地址

2.         如果堆中的地址够用,就将调用构造函数创建这个对象将把它放在内存指针指向的位置

3.         返回对象的引用,并将指针指向下一个对象应该存放的地址。

接下来到了垃圾回收了! 如果在计算新对象所用空间时发现空闲内在已经不够用了,那么.net就会调用垃圾收集程序做一次垃圾收集。CLR逐个排查不可达的对象,对么在托管堆中这个排查会浪费大量的时间,为了优化这个排查过程,将堆上的每一个对象对归属为某一个代中。CLR将内存中的对象分为0~2代(.net2.0中)。其中

0代指的是从来没有被标记过垃圾收集的新对象(一般是函数域内的对象,被视为最先收集的对象);

1代是指在上一次垃圾收集中没有被回收的对象

2代是在一次以上没有被回收的对象(一般是应该程序的根级)

当内存中没有位置了,垃圾收集器就开始依次调查和收集0代对象中是否有不可达对象,如果是不可达的,就将它清除,如果是可达的对象就将它标记为1;直到可以有足够的位置存放新对象,这时不一定所有的0代对象对被清除了,那么它们被标记为1代;(1代是否被标记为2代?)如果被0代对象全部排查过了了,还不够分配给新对象 ,那么就开始排查1代对象,没有被回收的1代对象被标记为2代。如果排查过1代对象仍然不够,就开始排查第2代,就是这样2代对象存在的时间很长。

注意:进行垃圾收集时.net会将正在运行的进程中的线程全部挂起,等待清理完了,再将它们释放。这样做的目的是确保应用程序在回收过程中不会访问堆。

posted @ 2010-01-05 09:38  慧致澜馨  阅读(958)  评论(2编辑  收藏  举报