1.如何判断对象是垃圾?
1.1 引用计数法
给每个对象加一个计数器,对象被引用则计数器+1。当对象的计数器不为0时,该对象就可以被看作垃圾,等待回收。
缺点:循环引用:A引用了B,B引用了A。
这个方法在主流虚拟机里未被使用。
1.2 可达性分析算法
我们可以将对象之间的互相引用看作一个有向图。从几个起点(被称作GC Roots)开始搜索,就知道哪些对象是被引用了,那么另外那部分没被引用的对象就可以被视为垃圾,等待回收。
GC Roots主要有以下几种:
1.被栈上引用的对象。比如局部变量
2.被类的静态变量(方法区)引用的对象
3.被类的常量(方法区)引用的对象
4.synchronized锁住的对象
等等。。。。
2.垃圾回收算法
第一章介绍了如何判断对象是垃圾。在这个基础上,我们就可以谈谈垃圾回收算法了。常见的GC算法如下:
2.1 标记——清除(mark-sweep)
步骤如下:
标记
根据GCRoots算法,标记哪些对象不是垃圾。
清除
清掉未被标记的对象。
-------------------------------
优缺点分析
优点:
原地回收,不用拷贝、移动对象,所以延迟低。
这样当该区域存活对象比较多的时候,就很适合用这种方法GC。因为拷贝对象的代价更大。那你一定想到了,老年代就很适合这种算法去GC。
缺点:
1.因为清除后没有整理空间,所以会造成空间碎片。容易引起FULL GC,FULL GC是会去整理、移动对象的。这样进程就会停顿(可以简称为STW),更可怕的是,STW的时间是未知的!
2.效率不稳定,与存活对象数量有关。
CMS垃圾收集器的老年代就是用的这种算法。
----------------------------
2.2 标记——复制(mark-copy)
步骤如下:
标记
根据GCRoots算法,标记哪些对象不是垃圾。
复制
将存活对象移动到另一块空余的空间,然后清除其他空间。是的,这种方法会占用多余的空间。
-------------------------------
优缺点分析
优点:
1.没有内存碎片的。比较适合存活对象较少的区域(年轻代)
缺点:
1.移动对象是耗时间的,而且需要停止进程的活动(STW)
2.需要额外消耗空间。
经典的Appel式回收将空间分为Eden区和Servivor区(两块相同大小,假设为Servivor1和Servivor2)。
对象首先在Eden区被创建(如果可以的话),GC时,将Eden区和Servivor1区的存活对象都移动到Servivor2区。然后清除Eden区和Servivor1区。
Servivor1区和Servivor2区是轮流存放存活对象的,下一次GC就是将Eden区和Servivor2区的对象都移动到Servivor1区了。
如果一块Servivor区放不下当次GC的存活对象怎么办?
部分对象可以丢到老年代去。当然老年代也不一定放得下。
2.3 标记——整理算法(mark-compact)
在标记-复制算法中,我们用到了额外空间。
那么可不可以不用额外空间呢?当然是可以的。本方法就是。
它与复制算法的区别就在于,他是在原空间里,把所有存活对象都移动到一端,接着清除另一端的数据。
那么你肯定想知道,为什么年轻代用复制算法而不用整理算法呢?
其实我不知道,因为书上没讲。
书上只说了:年轻代用复制算法,老年代用整理算法。
后面我又翻了别的资料,找到了这样一句话:说明复制算法还是快一点。
好吧,看来水很深我把握不住。有时间再去深入研究下。
-------------------------------
优缺点分析
优点:
1.内存无碎片。也不需要额外空间。
2.总的来说,提高了吞吐量,即:虽然浪费了时间去STW,但无碎片的内存空间使得内存的分配与访问更轻松。总的来说利大于弊。
缺点:
1.移动对象是耗时间的,而且需要停止进程的活动(STW),而且因为老年代存活数量多,STW时间会很长。
2.需要额外消耗空间。
那么这算法有人用吗?有的,G1收集器从整体上看就是这种思想,只是G1以更小的粒度进行回收,使得整理阶段时间短一点。
3.常见垃圾收集器
程序=算法+数据结构
垃圾收集器=GC算法+数据结构。
只介绍两种典型哈,面试吹吹水就行了,多了咱也记不住。
3.1 CMS(Concurrent Mark Sweep) 收集器
特点
名字里带Sweep,显然是基于标记-清除算法的。该算法在清除阶段是不用STW的,很快!
当然,会造成内存碎片,碎片太多就会导致大对象放不下。引起Full GC进行内存整理,而Full GC需要STW,更可怕的是这个STW时间是未知的,这就很危险了。
回收步骤
1.标记GCRoots可达的第一层对象,需要STW,但很快。
2.并发标记:不用STW,很耗时。
3.因为上一步没有STW,所以肯定会有数据不一致,如何处理数据不一致呢?CMS算法中使用了增量更新(反正我没看懂,有时间回来填坑)。
这一步也是SWT的,但也比较快。
4.并发清除
因为就地清除,不涉及到移动活对象,不用STW。清除算法快就快在这个地方!
3.2 G1(Garbage First)收集器
特点
CMS如今已不被看好,G1会变成他的替代者。
我们刚刚有提到,CMS可能会出现GC时间过长的情况,G1解决了这个问题。
我们指定一个最长回收时间,G1就能够算出哪些区域(region,G1将空间划分为一个个region,每个region可以是年轻代、老年代)可以被回收。
G1回收速度不如CMS,但是其系统吞吐量会更高(内存分配与访问的角度)。同时其回收时间可控,这是最关键的。
回收步骤
1.基本上同CMS。不同的是,每个region会单独划分出一块区域给新对象分配。
2.基本上同CMS,很耗时。与CMS不同的是,G1采用了SATB方法保证并发执行。
3.基本上同CMS,只不过是处理STAB数据。
4.回收。需要将存活的Region移动到空的Region,比较耗时了。
-------------
哎,这些资料都写的不详细,要不是为了面试我才不看呢。
本文参考资料:《深入理解java虚拟机》第三版