学习GC需要搞懂以下三个问题:
哪些内存需要回收,这个问题指向的就是堆空间当中存放着的对象实例,这一部分是可以动态变化的,所以GC的第一步就是需要判断在这个堆空间当中哪些对象还存活着
1.引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用,则计数器+1,当引用失效则计数器-1,当计数器为0,则GC可以进行回收
2.可达性分析算法:通过GC root作为起点,寻找一个对象被引用过程的引用链,当引用链的结果不可达的时候,说明该对象是可以被回收的
在JDK1.2之前,Java中的引用只有引用和没有引用两种情况,但是在开发过程中,我们往往需要更加复杂的场景,例如当我们内存空间足够的时候,我们就讲对应的对象存储在内存中,当我们内存不足的时候我们就把它进行回收,所以JDK1.2之后,开始对引用进行了区分,分成了以下四种形式
对于回收方法区它的性能肯定是不如回收堆空间来的简单,因为堆空间比方法区会更加消耗内存.但是对于方法区而言也是有两种东西需要回收的,一种是废弃常量,另一种是无用的类.相对的废弃常量判定方法比较简单,没有对它的引用,就说明该常量已经废弃,但是对于无用的类判定的方法就比较复杂,需要满足以下几个条件
综上所述:GC在方法区当中的回收对废弃常量来说还算比较划算,但是对于无用的类则是性价比比较低的,因为本来类加载器就是根据该类是否被用到,从而来将该类加载到内存当中的,然而如果该类已经不存在任何引用了,那么说明这部分的程序也已经基本跑到头了
1.标记-清除算法:正如算法名字,该算法分成了标记和清除两个部分,标记部分如上所述的引用计数算法,标记完成之后进行清除部分
2.复制算法:复制算法的做法就是将所有堆空间当中的内存都复制一遍,然后当这些对象被使用过后,就会把这些复制出来的全部都清除,优点就是运行高效,不必考虑内存碎片问题,(内存碎片在多个对象相互引用的过程中没有全部清除,最终产生内存碎片)缺点是会将整个堆内存空间缩小到原来的一半,从而付出了很大的内存消耗
3.标记-整理算法:标记整理算法跟标记清除算法类似,标记过程相同,不同的是标记的结果不是为了清除,而是为了让所有对象在内存空间当中有序的往一个方向移动,并且设定一个内存边界,只是对内存边界以外的进行清理
4.分代收集算法:分代收集算法并不是一种新的算法,而是根据不同的堆空间(新生代,年老代,永久代[方法区]),采用不同的算法.例如对于新生代而言采用复制算法比较合适,因为在这个空间意味着有较多的短时间引用的对象被不断的创建和销毁,相比之下年老代就更加适合使用标记-清除算法或者是标记-整理算法,对于那些已经有不断被引用,然而即将不再被引用的对象进行清理操作
对于我们最常用的JVM HotSpot,它本身也有自带了很多个GC,不同的GC会有不同的一些效用,可以进行搭配使用
Serial收集器是一个比较霸道的收集器,本身它在进行垃圾回收的时候是单线程操作的,它的单线程不仅仅是自己的单线程,它还会在运行前发起指令终止其他的线程,以达到它单线程的目的.所以它也有一个绰号叫做"stop the world"
ParNew收集器简单来说就是楼上的Serial收集器的升级版,相当于同时开启了多个Serial收集器去工作,其它方面并没有什么创新之处
Parallel Scavenge收集器是一个新生代的收集器,跟ParNew一样是一个多线程的收集器,但是它更强调的是可控的吞吐量,提供了可以用于控制平衡的吞吐量 吞吐量=CPU运行用户代码时间/CPU总耗时
Serial Old是Serial收集器的老年代版本,同样是单线程收集器,算法使用的是标记-整理算法,其余跟Serial收集器没有什么太大区别 本质上说垃圾收集器就是类似于妈妈在打扫房间,虽然你会觉得Serial收集的做法很霸道,当它在运行的时候就不允许其他线程运行,但是你想想,如果你妈妈在打扫房间的时候,你还在一边扔纸屑打扰她,试想一下是不是也很不合理
其实本质上就是Parallel Scavenge的收集器的老年代版本,采用的是标记-整理的算法
需要重点介绍的一款GC,在JDK1.5~JDK1.7之间基本采用的都是CMS作为GC来管理内存.全称是Concurrent Mark Sweep,顾名思义采用的是标记-清除的算法,目标是达到最短回收停顿时间.过程分成了4个步骤
初始标记和重新步骤仍旧需要"Stop the world",但是由于初始标记只是标记GC Roots的初始节点,所以速度会很快 CMS是一款十分优秀的收集器,也是目前B/S开发模式比较常用的GC收集器.它的特点是并发收集,低停顿.主要来源于它对CPU的敏感度给常高,它虽然不会导致用户的其它线程停顿,但是会导致其它应用程序变慢,吞吐量会变慢,CMS默认启动的回收线程数=(CPU数量+3)/4,当CPU数量为4的时候,那么资源占用为25%,但是当CPU数量小于等于2的时候,那么资源占用率就至少达到了72.5% 综上所述:对于高性能的服务器,具备4个以上的CPU来说,采用CMS垃圾收集器是非常可观的
从JDK1.7开始逐渐开始替代了CMS收集器在JavaGC中的地位.它具备了以下几个以前的那些GC没有的特点