gc垃圾回收机制整理

来源:互联网 发布:java最优二叉树 编辑:程序博客网 时间:2024/06/05 20:14

1、什么叫做垃圾回收

 

垃圾回收器负责回收所有无任何引用对象的内存空间。

注意:垃圾回收回收的是无任何引用的对象占据的内存空间而不是对象本身。

 

2、为什么要有GC

GC是垃圾收集的意思(GabageCollection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的

 

3、GC的工作原理


(一)、标记

目标:找出所有引用不为0(live)的实例

方法:找到所有的GC的根结点(GC Root),将他们放到队列里,然后依次递归地遍历所有的根结点以及引用的所有子节点和子子节点,将所有被遍历到的结点标记成live弱引用不会被考虑在内

(二)、计划和清理

1、计划

目标:判断是否需要压缩

方法:遍历当前所有的generation上所有的标记(Live),根据特定算法作出决策

2、清理

目标:回收所有的free空间

方法:遍历当前所有的generation上所有的标记(Live or Dead),把所有处在Live实例中间的内存块加入到可用内存链表中去

(三)、引用更新和压缩

1、引用更新

目标:将所有引用的地址进行更新

方法:计算出压缩后每个实例对应的新地址,找到所有的GC的根结点(GC Root),将他们放到队列里,然后依次递归地遍历所有的根结点以及引用的所有子节点和子子节点,将所有被遍历到的结点中引用的地址进行更新,包括弱引用。

2、压缩

目标:减少内存碎片

方法:根据计算出来的新地址,把实例移动到相应的位置。

 

4、什么类型变量需要垃圾回收

CLR在运行时管理着一段内存地址空间分为“托管堆”和“栈”两部分,栈用于存储值类型数据,它会在方法执行结束后自动销毁其中引用的值类型变量,这一部分不属于垃圾收集的范围。托管堆用于引用类型的变量存储,是垃圾收集的关键阵地。 

 

5、对象代龄

CLR初始化后的第一批被创建的对象被列为0代对象。CLR会为0代对象设定一个容量限制,当创建的对象大小超过这个设定的容量上限时,GC就会开始工作,工作的范围是0代对象所处的内存区域,然后开始搜寻垃圾对象,并释放内存。当GC工作结束后,幸存的对象将被列为第1代对象而保留在第1代对象的区域内。此后新创建的对象将被列为新的一批0代对象,直到0代的内存区域再次被填满,然后会针对0代对象区域进行新一轮的垃圾收集,之后这些0代对象又会列为第1代对象,并入第1代区域内。第1代区域起初也会被设上一个容量限制值,等到第1代对象大小超过了这个限制之后,GC就会扩大战场,对第1代区域也做一次垃圾收集,之后,又一次幸存下来的对象将会提升一个代龄,成为第2代对象。

6、手动处理编写代理代码:FinalizeDispose

Finalize Finalize是由GC负责调用,是一种自动的释放方式。

两个问题:

第一,  由于无法确定GC何时会运作,因此可能很长的一段时间里对象的资源都没有得到释放,这对于一些关键资源而言是非常要命的。

第二,  第二,由于负责调用Finalize的线程并不保证各个对象的Finalize的调用顺序,这可能会带来微妙的依赖性问题。如果你在对象aFinalize中引用了对象b,而ab两者都实现了Finalize,那么如果bFinalize先被调用的话,随后在调用aFinalize时就会出现问题,因为它引用了一个已经被释放的资源。因此,在Finalize方法中应该尽量避免引用其他实现了Finalize方法的对象。

可见,这种自动释放资源的方法并不能满足我们的需要,因为我们不能显示的调用它(只能由GC调用),而且会产生依赖型问题。我们需要更准确的控制资源的释放。

 

 

Dispose:是提供给我们显示调用的方法,如果确定占用内存,可以调用,由于Dispose方法可能被多线程调用,所以加锁以确保线程安全,但是不占用内存时,还是不需要调用的。

 

原创粉丝点击