名词介绍:
1.新生代GC Minor GC
指发生在新生代的垃圾回收动作,因为java对象大多都是创建快死亡也快,所有Minor GC 非常频繁,回收速度也快
2.老年代GC Major GC
指发生在老年代的垃圾回收动作,出现了MajorGC,经常至少会伴随着一次MinorGC也就是FullGC。Major GC的速度一般较慢
3.串行
指单线程进行垃圾回收工作,此时用户线程在等待
4.并发
指用户线程和垃圾回收线程在同一CPU上交替执行
5.并行
指用户线程和多条垃圾回收线程分别在不同的CPU上同时工作。
6.STW
stop the word 是指在垃圾回收时需要停止所有的线程,直至垃圾回收结束,
垃圾回收算法:
1.标记清除
分为标记和清除两个阶段,标记阶段变量堆中所有对象,将存活的对象标记。标记完成后再遍历堆中所有的对象,对未被标记的对象进行回收
缺点:因为直接回收未被标记的对象,所以会导致内存碎片。现在的虚拟机基本不用此算法。
2.复制算法
复制算法将内存空间划分为两个区间,所以的对象都放在其中的一块区间内。在垃圾回收时将存活的对象复制到空闲区间。扫描完毕后会将之前用过的区间一次性回收。
缺点:会浪费一般的内存空间。并且如果对象存活率比较搞时会进行多次复制,导致效率降低。因此适用于新生代的垃圾回收
3.标记整理算法
跟标记清除算法一样的方式先对存活对象进行标记,在标记完成后不是直接清除未标记的对象,而是将标记的对象移动到内存空间的另一端,并且更新指针。然后再清除另一端的内存空间
缺点:解决了标记清除算法的内存碎片问题,但是因为对存活对象移动排序整理,因此导致效率降低。
4.分代收集算法
现代虚拟机为了优化内存空间,使用了分代收集算法。根据对象的存活周期不同将堆划分为新生代和老年代。兵器根据老年代和新生代的特点采用不同的垃圾收集算法老年代一般使用标记清除或者标记整理算 法。新生代一般使用复制算法。
以Hotspot虚拟机为例,将新生代内存分为Eden S1 S2 三个区域,比例为8:1:1,在进行内存分配时只使用Eden和S1,在进行垃圾回收时将Eden和S1中存活的对象复制到S2区域。若S2区域内存不足时需要老年代 担保,将存活对象直接晋升为老年代。若S2区域空间足够,则每次移动会给对象年龄加一默认到15岁则进入老年代。
对象进入老年代的策略:年龄大于15的。占用连续内存交大的。S2区放不下。根据对象动态年龄判断如果某个年龄段的对象占S2区的一半以上那么比这个年龄段大的对象都会晋升老年代。例如1-3岁的大于一半 那么4岁以上的对象都会晋升老年代。
垃圾回收器
1.新生代垃圾回收器
Serial:单线程垃圾回收器,采用复制算法。因为单线程不需要进行线程切换所以适合用在单核机器上,存在STW
ParNew: 是Serial的多线程版本。采用的复制算法。适合搭配CMS作为老年代回收器使用。通过调整垃圾回收的线程数达到最优效果
Parallel Scavenger 多线程垃圾回收器。采用复制算法。不能与CMS一起搭配使用。通过设置的垃圾回收时间来达到吞吐量更高
2.老年代垃圾回收器
Serial Old: 单线程回收器,采用标记整理算法。
Parallel Old:Parallel Scavenger的老年代版本。多线程回收器,同样也是采用吞吐量优先的策略。
CMS:CMS回收器是在最短回收停顿时间为前提的回收器,属于多线程回收器,采用标记清除算法。
CMS垃圾回收过程 1.初始标记 仅仅是标记GC ROOTS 直接关联的对象。这个阶段速度很快,需要STW
2.并发标记,进行的是GC Tracing ,从GC ROOTS开始对堆进行可达性分析,找出存活对象
3.重新标记,重新标记阶段为了修正并发期间由于用户进行操作导致的标记变动的那一部分对象进行标记记录。这个阶段比初始标记时间长,但是小于并发标记。需要STW
4.并发清楚 清楚未标记的垃圾
CMS缺点:1.对CPU依赖太大,默认开启(CPU+3)/4个线程,对效率影响较大
2.CMS 回收器无法清除浮动垃圾。因为在清除过程中用户线程还会产生垃圾,这部分垃圾因为没有被标记所以不会被清除
3.会产生垃圾碎片,因为采用标记清除算法。可以搭配适当的内存整理策略。
4.一般会在老年代内存占用达到92%进行老年代回收。预留8%给浮动垃圾,入过8%不够则会使用serial old 回收器进行一次性回收垃圾会产生STW
3.G1回收器
G1将堆分为大小相等的Region,避免全区域垃圾回收,然后追踪每个Region垃圾堆积的价值大小,在后台维护一个优先列表,根据允许的回收时间回收价值最大的Region。同时G1存放Region之间的对象引 用,从而避免全堆扫描。
G1收集过程:1.初始标记 仅仅标记GC ROOTS内直接关联的对象。此过程速度很快,需要STW
2.并发标记 进行的是GC Tracing ,从GC ROOTS开始对堆进行可达性分析,找出存活对象
3.重新标记,重新标记阶段为了修正并发期间由于用户进行操作导致的标记变动的那一部分对象进行标记记录。这个阶段比初始标记时间长,但是小于并发标记。需要STW
4.筛选回收 首先对回收价值和回收成本进行排序,根据设置的停顿时间来定制回收计划。这阶段并发执行,但是因为只回收部分Region,时间是可控的,而且停顿用户线程能大幅提搞回收效 率。
G1相对其他收集器特点
1.并行与并发 使用多个CPU来缩短STW的停顿时间。其他收集器需要停顿java线程执行的GC动作,G1回收器可以通过并发的形式让java程序继续执行
2.分代回收 仍然保留分代概念,只不过没用到。可以通过不同的策略处理创建对象和已经存活过一段时间的对象,达到更好的回收效果。
3.空间整合 与CMS不同的是G1从整体来看是基于标记整理算法,然后每个region之间又是使用复制算法。
4.可预测的停顿,G1和CMS都追求低停顿,但是G1通过维护的优先列表,和价值大的region来建立可预测的停顿时间。
JVM 内存区域划分
1.线程私有
程序计数器:记录当前线程所运行的字节码行号指示器,也就是虚拟机字节码指令
本地方法栈:记录虚拟机用到的native方法
栈:本地方法栈,用于存储局部变量,操作数栈,动态链接,方法出口等信息
2.线程共享
堆:jvm堆属于线程共享的区域,在虚拟机启动时创建,是Java虚拟机管理内存中最大的一块,主要用于存放对象实例,堆是垃圾回收器管理的主要区域。如果堆无法给程序分配内存时会抛出 OutOfMemoryError,异常。
方法区:用于存放类信息,常量,静态常量和即时编译后的代码数据
运行时常量池:是方法区的一部分,用于存储编译期间生成的各种字面量和符号引用。
垃圾收集算法:
1.引用计数算法 这种算法为堆中每个对象创建一个引用计数器,当一个对象被创建时,将引用计数器赋值为1,当有其他地方引用改对象时就会给计数器加1。当改该象的引用超过该对象生命周期时或者被设 置新值时计数器减一,任何计数器为0的对象都可以被回收。当一个对象被垃圾回收是他引用的任何对象的计数器都减一。
缺点:无法解决循环依赖A-B,B-A。
优点:执行效率高
2.可达性分析算法 从GCROOS开始,寻找对应的引用节点,直至找到所有的引用节点。剩余的节点则是可以回收的节点。在确定为可回收后节点时会进行两次标记。第一次标记是进行可达性分析后没有 GCROOTS相连接的引用。第二次标记是,在进行第一次标记完会进行筛选,筛选的条件是是否有必要进行finalize,在finalize方法里没有引用则进行第二次标记,经过两次标记的对象将会被回收。
3.GCROOTS 栈中的引用对象,方法区中类静态属性引用的对象,本地方法栈自己中的引用对象,方法区中的常量对象等等(被同步锁持有的对象)
4.方法区的垃圾回收
分为无用类和废弃常量,针对废弃常量可使用可达性分析算法,对弈无用类需要满足几个条件才可以,第一是所有的实例都被回收。第二加载该类的classload被回收。第三改类对应的class对象没有在任何地 方被引用