垃圾回收指的是jvm堆内存和方法区的回收,这些区域内存在程序运行期间动态分配、动态回收,需要考虑选择合适的垃圾回收算法。
如何判断对象是否已经消亡
1 引用计数法
在Java中,引用和对象是有关联的。如果要操作对象则必须用引用进行。因此,很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收。简单说,即一个对象如果没有任何与之关联的引用,即他们的引用计数都不为0,则说明对象不太可能再被用到,那么这个对象就是可回收对象。这种方法有个缺点就是无法检测到引用环的存在。
2 可达性分析算法
为了解决引用计数法的循环引用问题,Java使用了可达性分析的方法。通过一系列的“GCroots”对象作为起点搜索。如果在“GCroots”和一个对象之间没有可达路径,则称该对象是不可达的。
要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收。
左图中每个对象都存在引用链与GCRoots相连,表明对象还在,不能回收。
右图中三个对象虽然互相引用,但是没有链接与GCRoots相连,则可判断它们是可回收的对象。
常用垃圾回收算法
1 标记-清除算法 mark and sweep
mark阶段从引用根节点开始标记所有被引用的对象,寻找引用链,即仍然活着的对象。sweep阶段直接将未标记的对象清除。该算法的缺点是需要停顿整个应用(stoptheworld),而且容易产生内存碎片。
2 标记-复制算法 mark and copying
此算法把内存划分为相等大小的两个区域,每一只使用其中一个,回收过程中将存活的对象全部复制到另一个区域中,清空原区域。在年轻代中eden区和两个survivor区就是使用了此种算法。这种算法只复制存活的对象,成本较低,而且不会出现内存碎片问题,缺点是需要2倍的内存空间
3 标记-整理算法 mark and compact
该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。所以,特别适用于存活对象多,回收对象少的情况下。效率比“标记-清理”算法低,但不会产生内存碎片。
4 分代收集算法
分代收集算法是目前大部分JVM的垃圾收集器采用的算法,根据不同代的特点采取最适合的收集算法,年轻代的回收算法是复制算法,年老代的回收算法是标记回收算法