GC常见垃圾回收算法,JVM分代模型

如何判断是垃圾?引用计数器和Root可达性算法

如何进行清除?标记清除、复制、标记整理

堆分代模型?Eden,Surevivor,Tenuring

一个对象从创建到消亡的过程?

对象什么时候进入老年代?

一、GC(Garbage Collector)

GC tuning:GC调优

tuning:调整,调优

reference:引用

1、Garbage,什么是垃圾?

没有引用指向的任何对象,都是Garbage

2、判断什么是垃圾的两种算法(也就是怎么找到垃圾):

(1)reference count(引用计数器):

有一个对象引用该变量,在对象头+1,有多个就加多个,没引用了就-1,减到0,说明没有引用了,判定为垃圾;

reference count不能解决的问题是循环引用问题,比如对象A引用对象B,对象B引用对象C,对象C又引用对象A;

相互引用的时候没有任何第三方对象引用这两个对象,不能判断为垃圾,不会被回收,实际上是需要被回收的:

(2)root searching(可达性算法):

在编程过程中哪些对象或者变量会被定义成root?

JVM Stack:虚拟机栈里面的线程栈里面的变量;

Native Stack:c/c++实现的那些native方法里面使用到的变量,会被定义为root对象

静态变量:static修饰的对象

常量池里面的对象:比如Class对象

一般是一个程序启动后马上要用到的对象;

3、找到垃圾之后,如何进行清除?

三种算法:(优缺点是指这种算法的优缺点)

(1)Mark Sweep:标记清除,

特点:

  • 从Root对象开始,遍历两次,一次进行标记,一次进行清除;
  • 算法简单;执行效率不稳定,垃圾较多,而存活对象少的时候,效率低,内存空间碎片化会更严重;

(2)为解决Mark Sweep算法的缺陷,提出:Semispace Copying:拷贝(半区复制算法)

实现:

  • 将内存一份为二,从Root对象开始,将有用的对象移动(复制)到一边,移动完成后清除另一边需要被回收的内存;当垃圾较多,存活对象较少时,只需要将存活对象移动到一块很小的区域,就能进行垃圾清除,效率高,同时也能解决内存空间碎片化的问题;
  • 只扫描一次,但移动复制对象,需要调整对象的引用,会产生对象引用指针移动的开销,同时将内存一分为二,也会造成内存减半的后果,空间浪费;
  • 如果存活对象比较多的情况下不适合;
  • 如果存活对象比较多,内存又减半会导致内存不足,需要老年代进行分配担保(当Eden进行回收后往Surivor区进行复制,Surivor区发现内存不足,对象直接进入老年代)

(3)Mark Compact:标记整理

实现及特点:

  • 扫描2次,从Root开始将有用的对象压缩到内存的头部,如果前面有垃圾进行填充
  • 需要移动对象,效率偏低;
  • 不会产生内存碎片,更方便对象分配,不会产生内存减半;

总结:标记清除和标记整理的算法

  • 是否移动对象:移动则回收的时候更复杂,不移动则内存再分配时会更复杂
  • 是否停顿(或者说停顿时间更短):移动的时候停顿时间更长,不移动的时候停顿时间短,甚至可以不停顿;
  • 吞吐量:从吞吐量的角度考虑,移动对象吞吐量会更高;
  • 也就是说,根据业务,如果在意用户体验,不要停顿太长时间的情况下,考虑使用不移动对象的垃圾回收算法,也就是标记-清除
  • 如果对吞吐量要求高的场景,使用移动对象的垃圾回收算法,也就是复制或者标记整理的垃圾回收算法会更划算;

二、JVM内存分代模型

1、堆内存的逻辑分区

G1是逻辑分代,但物理内存不分代,除此之外,都是逻辑分代,物理内存也分代

Eden区是new出来的对象真正存放的区域,而S0和S1是经过回收会还存活的对象存在区域

GC算法的选择上,新生代活着的对象比较少适合Copying算法的垃圾回收器,而老年代 ,存活的对象比较多,适合Mark Sweep(MS)和Mark Compact(MC)这两种算法实现的垃圾回收器;

查询年轻代和老年代之间的空间比值:NewRatio=2,意思是年轻代和老年代的比值是1:2:

java查询参数小细节:java -XX:PrintFlagsFianl -version

以-开头的标准参数

以-X开头是非标准参数,

以-XX开头,不稳定参数,有些版本支持,有些版本可能不支持,也可能不是这个命令

2、一个对象从创建到消亡的过程:

先尝试栈上分配,如果满了,在Eden区分配,当出现GC时,会往S0区域移动,多次回收是指在S0和S1上来回移动,移动次数可以通过参数配置,经过多次回收还存活,移动到老年代;

MinorGC/YGC: 年轻代垃圾回收,年轻代空间耗尽,无法再分配空间时,触发该GC;

Major/FullGC: 老年代和年轻代都空间耗尽,无法再分配空间时,老年代和年轻代都会触发GC;

3、对象尝试在栈上分配

(1)什么样的内容会在栈上分配?

  • 线程私有小对象:对象比较小,而且是线程私有的,没有线程共享
  • 无逃逸:出了线程无其他线程知道这个对象的存在
  • 支持标量替换:对象只有少量属性,完全可以使用这些属性来替换对象;

(2)当线程栈上分配空间不足了,会进行线程本地分配(Thread Local Allocation Buffer,简称TLAB)

  • 每个线程会在Eden区有一块小区域是该线程独享的,用于分配小对象,仅1%;
  • 多线程的时候不用竞争Eden区域就可以申请的空间,可以提升对象分配的效率;

4、对象什么时候进入老年代?以下两种情况会进入老年代

(1)通过一个参数设置:XX:MaxTenuringThreshold指定回收次数,也就是当进行GC时,对象在S0和S1之间进行copying,超过该参数设置的值,就会触发对象进入老年代;

该参数,在

Paralle Scavenge中默认是15

CMS:6

G1:15

(2)动态年龄,是指将S0里面的存活对象全部拷贝到S1的时候,如果发现全部对象的大小超过了S1的空间的50%,则会触发动态年龄淘汰机制,就是把年龄最大的那些对象放入老年代,而不管他的copying次数是否超过设置的阈值;

相关推荐
Felix_XXXXL12 分钟前
集成RabbitMQ+MQ常用操作
java·后端
Learn Beyond Limits18 分钟前
Regression vs. Classification|回归vs分类
人工智能·python·算法·ai·分类·数据挖掘·回归
修行者Java18 分钟前
JVM 内存结构的详细介绍
jvm
hygge99919 分钟前
JVM GC 垃圾回收体系完整讲解
java·开发语言·jvm·经验分享·面试
不去幼儿园29 分钟前
【强化学习】可证明安全强化学习(Provably Safe RL)算法详细介绍
人工智能·python·算法·安全·机器学习·强化学习
Fantasydg44 分钟前
MyBatis学习
java·学习·mybatis
月疯1 小时前
自相关实操流程
人工智能·算法·机器学习
qk学算法1 小时前
Collections工具类
java·开发语言
青云交1 小时前
Java 大视界 -- 基于 Java 的大数据可视化在企业生产运营监控与决策支持中的应用
java·echarts·数据采集·实时监控·大数据可视化·智能决策·企业生产运营