一.两种回收策略
-
引用计数法
给对象添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任何时候计数器为0的对象就是可被回收的对象.
该方法实现简单,效率高,但是目前主流的虚拟机中并没有采用该策略管理内存,最主要的原因是它很难解决对象直接相互循环引用的问题,但是它们由于相互引用导致计数器都不为0,于是引用计数器无法通知GC回收器回收它们. -
可达性分析算法
将"GC Roots"对象作为起点,从这些夹断开始向下搜索引用的对象,找到的对象全部标记为非垃圾,其余未标记的对象都是垃圾对象.
GC Roots的判断方法:一般为线程栈的本地变量,静态变量,本地方法栈的变量等等.
二.垃圾回收算法
-
1标记清除算法
特点:清除后空闲位置不连续,容易产生碎片
-
2复制算法
特点:将内存分割,存活对象复制到没有使用过的另一半内存中,可回收的对象的清除,虽然降低了碎片,但是空间使用率低
-
3标记整理
特点:将内存中可回收对象标记回收后把存活对象进行整理,虽然没有碎片但是效率低
常用垃圾回收器
图中连线表示可以配对使用
java1.8之前的堆内存采用分代的概念.
serial采用单线程复制算法,暂停所有用户线程,用于新生代
serial old采用单线程标记整理算法,暂停所有用户线程,用于老年代
parallel scavenge和parallel old(PSPO)是1.8默认收集器
parallel scavenge采用多线程复制算法,暂停所有用户线程,用于新生代
parallel old采用多线程标记整理算法,暂停所有用户线程,用于老年代
上述两种都会导致用户线程暂停!
par new 采用采用多线程复制算法,暂停所有用户线程,用于新生代
CMS (ConcurrentMarkSweep)采用标记清除算法
- 第一阶段:标记gcRoots连接的第一个对象(该过程会暂停所有用户线程,但时间极短)
- 第二阶段:并发标记,继续沿第一阶段标记的对象往下标记(该过程和用户线程并发,可能会产生浮动垃圾甚至误标垃圾,浮动垃圾可在下次GC回收)
- 第三阶段:重新标记,解决误标垃圾问题(该过程会暂停所有用户线程,但时间极短)
- 第四阶段:并发清理,清理垃圾(该过程和用户线程并发,考虑极端情况下,此时老年代新的垃圾放不下,会立即终止CMS,转而采用serial old替补)
CMS的效率在毫秒级
java1.8之后没有分代的概念,只有分区的概念
java1.9默认收集器G1特点是一边运行一边回收 比CMS效率更高
java1.9及以后的垃圾回收器且听下回分解