垃圾收集器与内存分配策略

1、如何判断对象已死?
1.1、引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用过它时,计数器值就加1,当引用失效时,计数器值就减1,任何时刻计数器都为0的对象不可能再被使用。优点:效率很高,缺点:很难解决对象之间的相互循环引用的问题。
1.2、根搜索算法:通过一系列的名为“GCRoots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GCRoots没有任何引用链相连(用图论的话来说就是从GCRoots到这个对象不可达)时,则证明此对象是不可用的。
可作为GCRoots的对象包括下面几种:
虚拟机栈(栈帧中的本地变量表)中的引用的对象。
方法区中的类静态属性引用的对象。
方法区中的常量引用的对象。
本地方法栈中JNI(即一般说的Native方法)的引用对象。
生存还是死亡,在根搜索算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“死缓”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程
2、回收方法区,方法区属于永久代,而永久代的垃圾收集效率低。永久代垃圾收集主要回收两部分:废弃常量和无用的类,
废旧常量:没有任何String对象引用常量池中的“abc”常量,这个“abc”常量就会被系统‘请’出常量池,常量池中的其他类(接口)、方法、字段的符号引用也与此类似。
无用的类:该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。
加载该类的ClassLoader已经被回收
该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
3、垃圾收集算法
3.1、标记-清除算法(Mark-Sweep)算法:首先标记出所有需要回收的对象,在标记完成后同一回收掉所有被标记的对象,缺点:效率问题
3.2、复制算法:将可以用内存按容量划分为大小相等的两块,每次只是用其中的一块,当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后徐再把自己使用过的内存空间一次清理掉。(实用于新生代)
3.3、标记-整理算法:实用于老年代,
3.4、分带收集算法:根据对象的存活周期的不同将内存划分为几块。一般是把java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。
4、垃圾收集器
【垃圾收集器与内存分配策略】4.1、serial收集器:虚拟机新生代收集的唯一选择,是一个单线程的收集器,
4.2、ParNew收集器:就是Serial收集器的多线程版本,除了使用多线程进行过垃圾收集之外,其余行为包括Serial收集器可用的所有控制参数(例如:-XX:SurvivorRatio、-XX:PretenureSizeThreshold、-XX:HandlePromotionFailure等)、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全一样,实现上这两种收集器也共用了相当多的代码。(使用新生代收集器)
4.3、Parallel Scagenge收集器也是新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器,目的测试达到一个可控制的吞吐量。停顿时间越短越适合需要与用户交互的程序,良好的响应速度能提升用户的体验,而高吞吐量则可以最高效率的利用CPU时间,尽快的完成程序的运算任务,主要适合在后台运算而不需要太多的交互的任务。-XX:MaxGCPauseMillis:控制最大垃圾收集停顿时间,-XX:GCTimeRatio设置吞吐量大小。
4.4、Serial Old收集器是Serial收集器额老年代版本,同样是一个单线程收集器,是用“标记-整理”算法。
4.5、Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
4.6、CMS收集器(Concurrent Mark Sweep)是一种以获取最短回收停顿时间为目标的收集器。基于“标记-清除”算法实现的,
整个过程分为4个部分:
1、初始标记(CMS initial mark)2、并发标记(CMS concurrent mark)3、重新标记(CMS remark)4、并发清除(CMS concurrent swepp)
其中初始标记、重新标记这两个步骤仍然需要“stop the world”。初始标记仅仅只是标记一下GCRoots能直接关联到的对象,速度很快,并发标记阶段就是进行GCRoots Tracing的过程,而重新标记阶段则是为了修正并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
4.7、G1收集器:一是G1收集器是基于“标记-整理”算法实现的收集器,也就是说它不会产生空间碎片,这对于长时间与性格的应用过系统来说非常重要,二是可以非常精确地控制停顿,既能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过M毫秒,这几乎已经是实时java(RTSJ)垃圾收集器的特征了。
G1将整个java堆(包括新生代,老年代)划分为多个大小固定的独立区域(Region),并且跟踪这些区域里面的垃圾堆积成都,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域(这就是Garbage First名称的来由)。

    推荐阅读