JAVA基础--垃圾回收机制及算法

来源:互联网 发布:sql cast函数有什么用 编辑:程序博客网 时间:2024/06/05 22:35

一、垃圾回收机制的作用

主要有两个作用:

  1、跟踪并监控每个Java对象,当某个对象处于不可达状态时,回收该对象所占用的内存。

2、清理内存分配、回收过程中产生的内存碎片。

二、那些对象可以被回收

只要该对象还被引用(这里应该指强引用),就不能被回收。当一个对象没被引用时,GC就会尝试回收它。

那么,又怎么判断一个对象是否存活。这里说两种方法:

1、引用计数算法

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器值减1;任何时刻计数器位0的对象就是被可能再被引用的。(缺点是:很难解决对象之间相互循环引用的问题。)

2、可达性分析算法(主流应用)

通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,此对象无用。


Java中可作为GC Roots的对象有下面几种:

(1)虚拟机栈(栈帧中的本地变量表)中引用的对象。

(2)方法区中类静态属性引用的变量。

(3)方法区中常量引用的对象。

(4)本地方法栈中JNI(即一般说的Native方法)引用的对象。

在这强调一点:及时在可达性分析算法中不可达的对象,也不一定非得被回收。

此时要判断此对象是否有必要执行finalize()方法。finalize就是一个对象的遗书,你把一个对象给杀了总的让他说点什么把。这个遗书可以把自己复活,另外如果在这个方法抛异常会导致此对象的终结操作停止,这两种都是死而复生的手段。

三、垃圾收集的基本算法

1、标记-清除算法

算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

缺点主要有两个:(1)效率问题:标记和清除两个过程的效率都不高。

(2)空间问题:标记清除之后会产生大量不连续的内存碎片,空间碎片大多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前出发另一次垃圾收集操作。


2、复制算法(解决效率问题)

它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后在把已使用过的内存空间一次清理掉。(每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可)

缺点:将内存缩小为了原来的一般,代价过高。


3、标记-整理算法

其过程与“标记-清除算法”相同,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界意外的内存。



4、分代收集算法(根据对象生存时间的长短,把堆内存分成三个代)

(1)Young代--新生代

采用复制算法只需遍历那些处于可达状态的对象,而且这些对象的数量较少,时刻复制成本也不大,因此可以充分发挥复制算法的优点。


(2)Old代--老年代

若一个对象经过足够长的时间还处于可达状态,垃圾回收机制就会将这个对象转移到Old代。

  特点:①Old代垃圾回收的执行效率无须太高,因为很少有对象会死掉。

      ②每次对Old代执行垃圾回收都需要更长的时间来完成。

就如上面所说,老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或者“标记-整理”算法来进行回收。


(3)Permanent代--永生代

Permanent代主要用于装在Class、方法等信息,默认为64MB,垃圾回收机制通常不会回收Permanent代中的对象。

0 0
原创粉丝点击