JVM系列:垃圾收集器与内存分配策略

2018-03-20  本文已影响0人  内卷星球

判断对象是否存活

引用计数算法

实现简单,判定效率高

Java虚拟机没有使用,主要原因是此算法很难解决对象之间相互循环引用的问题

可达性分析算法

通过一系列的称为"GC Roots"的对象作为起始点,从这些节点向下搜索,搜索走过的路径称为引用链;当一个对象跟"GC Roots"没有任何引用链的关系,则证明此对象不可达。

在进行可达性分析后发现此对象没有与"GC Roots"相连的引用链,则会被第一次标记并且进行一次筛选,条件是此对象是否有必要执行finalize()方法。
当对象没有覆盖finalize()方法,或者说finalize()方法已被虚拟机调用过,则没有必要执行
如果该对象判定有必要执行,则会放到F-Quene队列,并在稍后由一个虚拟机自动建立、低优先级的Finalize线程去执行(会触发,但并不一定会等这个方法执行结束,以避免该方法执行缓慢或者死循环)
finalize方法是对象逃脱死亡的最后一次机会,GC会对F-Quene中的对象进行第二次小规模标记,只有重新与引用链上的任何一个对象建立关联, 那么第二次标记,将会被移出"即将回收"集合,否则,就进行回收。
一个对象的finalize方法只会被虚拟机调用一次

在Java中,可作为"GC Roots"的对象包括下面几种:

引用又分为:强、软、弱、虚

回收方法区

永久代的垃圾收集主要是:废弃常量和无用的类

无用的类:

垃圾收集算法

标记-清除---->老年代

效率不高,产生大量不连续内存碎片

复制---->新生代

实现简单,运行高效,但是将内存缩小了一半

将可用内存划分为(A,B)2块,每次只用A块,将A块存活对象复制到B块,然后将A块一次清理,每次都对半区进行回收

标记-整理---->老年代

垃圾收集器

Serial收集器

单线程:进行垃圾收集时,必须暂停其他所有的工作线程,直到收集结束。
在Client模式下,简单高效,没有线程交互的开销

ParNew收集器

Serial收集器的多线程版本

Parallel Scavenge收集器

使用复制算法,达到可控制的吞吐量

Serial Old收集器

使用标记-整理算法

Parallel Old收集器

使用标记整理算法

CMS收集器

以获取最短回收停顿时间为目标的收集器

步骤:

G1收集器

面向服务器应用的垃圾收集器

特点:

将Java堆划分为多个大小相等的独立区域Region,G1跟踪各个Region里面的价值大小(回收获得的空间大小以及需要花费的时间的经验值),在后台维护一个优先列表,每一次根据允许的收集时间(可预测的停顿)优先回收价值最大的Region(每个Region都有Remembered Set 避免全堆扫描)

步骤:

内存分配与回收策略

内存分配的2种方式:

选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定

内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值

对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配,少数情况下分配到老年代

对象优先在Eden区分配

当Eden区没有足够的空间分配时,虚拟机将会发起一次Minor GC(新生代GC,速度较快)

大对象直接进入老年代

长期存活对象将进入老年代

年龄计数器:在Survivor没熬过一次Minor GC,年龄加1,当达到阈值,则进入老年代;阈值设置(-XX:MaxTenuringThreshold)

动态对象年龄判定

如果Survivor 中相同年龄所有对象的大小总和大于Survivor空间的一半,年龄大于或者等于该年龄的对象都直接进入老年代

空间分配担保

在Minor GC,虚拟机会检查老年代中最大可用的连续空间是否大于新生代所有对象总空间。如果成立,则Minor GC安全;不成立,查看HandlePromotionFailure是否允许担保失败;如果允许,则检查老年代可用连续空间是否大于之前每次晋升老年代的平均值大小,如果大于,则冒险进行Minor GC,如果小于或者设置不允许担保失败的话,则进行Full GC。

上一篇 下一篇

猜你喜欢

热点阅读