java垃圾回收机制(一)

垃圾回收的主要算法:

  1. 引用计数器
  2. 可达性分析算法

回收算法

  1. 标记清除(Mark-Sweep)

    产生空间碎片

  2. 复制算法(Copying)

    浪费内存空间

  3. 标记整理(mark-Compact)

    没有碎片,相对较慢(压缩内存的时间)

    区别:标记清除 位置不连续 产生碎片

    ​ 复制算法 没有碎片 浪费空间

    ​ 标记整理 没有碎片 效率较低

JVM内存模型

在这里插入图片描述

​ 分代模型:jdk1.8以及以前版本

​ 分区模型:jdk1.9以及以后版本

​ 将堆内存分为一小部分一小部分的区域进行管理;

年轻代和老年代

在这里插入图片描述

在这里插入图片描述

年轻代

  • 年轻代的中间的垃圾回收器是串行回收,就是单线程处理;
  • 第三列是并行回收,效率较快
  • 第一列的ParNew是对第三列的并行回收进行优化,最重要的是下面老年代的CMS垃圾回收器。

老年代

  • G1垃圾回收器是jdk1.7提出的效率快的垃圾回收机制;在jdk1.9时设置为java GC 的默认垃圾回收器,取代CMS;

  • java9默认号称STW时间不超过10ms;

  • ZGC:STW时间1ms

  • 同时在新老生代工作的垃圾回收器:G1

图片中的垃圾收集器如果存在连线,则代表它们之间可以配合使用,接下来我们来看看各个垃圾收集器的具体功能。

在这里插入图片描述

  • 应用程序中会一直存活的对象:

    • 经历过15次GC没被干掉的对象:
      • 数据库连接池
      • Spring的bean
      • 缓存对象
  • 大对象(配比可以设置 ,根据堆内存的大小)

    • 占用内存比较大的情况下,直接放入老年代

垃圾回收线程

  • 年轻代时Yougth GC 操作速度快,STW时间短,对应用影响不大;

  • 老年代满了就是开启full GC ,对全部堆内存进行全部GC ,STW时间长,影响用户体验度。

年轻代基本都是复制算法,老年代基本都是标记整理算法

栈内存的分配

大部分的对象都很短命,都在很短的时间内都被回收了(IBM 专业研究表明,一般来说,98% 的对象都是朝生夕死的,经过一次 Minor GC 后就会被回收),所以分代收集算法根据对象存活周期的不同将堆分成新生代和老生代(Java8以前还有个永久代),默认比例为 1 : 2,新生代又分为 Eden 区, from Survivor 区(简称S0),to Survivor 区(简称 S1),三者的比例为 8: 1 : 1,这样就可以根据新老生代的特点选择最合适的垃圾回收算法,我们把新生代发生的 GC 称为 Young GC(也叫 Minor GC),老年代发生的 GC 称为 Old GC(也称为 Full GC)。

年轻代和老年代的内存占比为1:2

年轻代分为伊甸园区和幸存区(Survivor);幸存区分为S0和S1

在这里插入图片描述

Stop-the-World,简称STW

指的是GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应, 有点像卡死的感觉,这个停顿称为STW。

  • STW事件和采用哪个GC方式无关,所有的GC都有这个事件。

  • 哪怕是G1也不能完全避免STW情况的发生,只能说垃圾回收器越来越优秀,回收效率越来越高,尽可能地缩短了暂停时间。

  • STW是JVM在后台自动发起和自动完成的。在用户不可见的情况下,把用户正常的工作线程全部停掉。开发中不要用System.gc() ;会导致STW的发生。

年轻代的STW时间少,可以忽略不计,尽量避免Full GC的出现。

常用的垃圾收集器

参考敖丙:https://mp.weixin.qq.com/s/_AKQs-xXDHlk84HbwKUzOw

年轻代垃圾回收器
Serial收集器

Serial 收集器是工作在新生代的,单线程的垃圾收集器,单线程意味着它只会使用一个 CPU 或一个收集线程来完成垃圾回收,

都会产生STW时间

Serial: 新生代采取复制算法,暂停所有用户进程

在这里插入图片描述

看起来单线程垃圾收集器不太实用,不过我们需要知道的任何技术的使用都不能脱离场景,在 Client 模式下,它简单有效(与其他收集器的单线程比),对于限定单个 CPU 的环境来说,Serial 单线程模式无需与其他线程交互,减少了开销,专心做 GC 能将其单线程的优势发挥到极致,另外在用户的桌面应用场景,分配给虚拟机的内存一般不会很大,收集几十甚至一两百兆(仅是新生代的内存,桌面应用基本不会再大了),STW 时间可以控制在一百多毫秒内,只要不是频繁发生,这点停顿是可以接受的,所以对于运行在 Client 模式下的虚拟机,Serial 收集器是新生代的默认收集器。

ParNew收集器

ParNew 收集器是 Serial 收集器的多线程版本,除了使用多线程,其他像收集算法,STW,对象分配规则,回收策略与 Serial 收集器完成一样,在底层上,这两种收集器也共用了相当多的代码,

在这里插入图片描述

在多 CPU 的情况下,由于 ParNew 的多线程回收特性,毫无疑问垃圾收集会更快,也能有效地减少 STW 的时间,提升应用的响应速度。

ParNew 主要工作在 Server 模式,我们知道服务端如果接收的请求多了,响应时间就很重要了,多线程可以让垃圾回收得更快,也就是减少了 STW 时间,能提升响应时间,所以是许多运行在 Server 模式下的虚拟机的首选新生代收集器,另一个与性能无关的原因是因为除了 Serial 收集器,只有它能与 CMS 收集器配合工作,CMS 是一个划时代的垃圾收集器,是真正意义上的并发收集器,它第一次实现了垃圾收集线程与用户线程(基本上)同时工作

Parallel Scavenge 收集器

Parallel Scavenge 收集器也是一个使用复制算法多线程,工作于新生代的垃圾收集器,看起来功能和 ParNew 收集器一样

CMS 等垃圾收集器更适合用到与用户交互的程序,因为停顿时间越短,用户体验越好,而 Parallel Scavenge 收集器关注的是吞吐量,所以更适合做后台运算等不需要太多用户交互的任务。

Parallel Scavenge 收集器提供了两个参数来精确控制吞吐量,分别是控制最大垃圾收集时间的 -XX:MaxGCPauseMillis 参数及直接设置吞吐量大小的 -XX:GCTimeRatio(默认99%)

除了以上两个参数,还可以用 Parallel Scavenge 收集器提供的第三个参数 -XX:UseAdaptiveSizePolicy,开启这个参数后,就不需要手工指定新生代大小,Eden 与 Survivor 比例(SurvivorRatio)等细节,只需要设置好基本的堆大小(-Xmx 设置最大堆),以及最大垃圾收集时间与吞吐量大小,虚拟机就会根据当前系统运行情况收集监控信息,动态调整这些参数以尽可能地达到我们设定的最大垃圾收集时间或吞吐量大小这两个指标。自适应策略也是 Parallel Scavenge 与 ParNew 的重要区别!

老年代垃圾回收器
Serial Old:

Serial 收集器是工作于新生代的单线程收集器,与之相对地,Serial Old 是工作于老年代的单线程收集器,此收集器的主要意义在于给 Client 模式下的虚拟机使用,如果在 Server 模式下,则它还有两大用途:一种是在 JDK 1.5 及之前的版本中与 Parallel Scavenge 配合使用,另一种是作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用(后文讲述)

Paralldl Old

Parallel Old 是相对于 Parallel Scavenge 收集器的老年代版本,使用多线程和标记整理法,两者组合示意图如下,这两者的组合由于都是多线程收集器,真正实现了「吞吐量优先」的目标

在这里插入图片描述

ParNew基本和Paralldl Scavenge 相同

ParNew的出现是Parallel的升级版,和CMS搭配使用,更好减少STW时间

CMS

(ConcurrentMarkUPSweep)

​ 作用于老年代,有四大核心标志

  1. 初始标记:有STW产生(短暂),标记Root
  2. 并发标记:不会产生STW
  3. 重新标记:处理错标和漏标(浮动垃圾)
  4. 并发清理:

在这里插入图片描述

图中两次会有STW,在初始标记和重新标记时候,初始标记仅标记的是GC Root关联的对象,速度很快,但是重新标记进行修正在并发标记的各种意外发生,所以这一阶段停顿时间一般比初始标记阶段稍长,但远比并发标记时间短

整个过程中耗时最长的是并发标记和标记清理,不过这两个阶段用户线程都可工作,所以不影响应用的正常使用,所以总体上看,可以认为 CMS 收集器的内存回收过程是与用户线程一起并发执行的。

浮动垃圾:

在这里插入图片描述

因为在并发标记的时候时不产生STW,可能会有进程产生状态的变换或者是新对象的产生或者别的情况。可能会在并发标记是产生。

​ 产生因为在CMS情况有并发处理,标记和用户进程会同时运行,难免有新的对象产生或者新的垃圾生成;

​ 处理方法是在CMS的重新标记时候产生STW在对所有的对象进行重新标记。

CMS的缺点:

  • CMS 收集器对 CPU 资源非常敏感
  • 无法处理浮动垃圾
  • CMS采用的是标记清除法,上文我们已经提到这种方法会产生大量的内存碎片,这样会给大内存分配带来很大的麻烦,如果无法找到足够大的连续空间来分配对象,将会触发 Full GC,这会影响应用的性能。
G1(Garbage First) 收集器

G1:目前比较好的垃圾回收机制

​ 面向服务端的应用的垃圾回收器

G1 收集器是面向服务端的垃圾收集器,被称为驾驭一切的垃圾回收器,主要有以下几个特点

  • 像 CMS 收集器一样,能与应用程序线程并发执行。
  • 整理空闲空间更快。
  • 需要 GC 停顿时间更好预测。
  • 不会像 CMS 那样牺牲大量的吞吐性能。
  • 不需要更大的 Java Heap

与 CMS 相比,它在以下两个方面表现更出色

  1. 运作期间不会产生内存碎片,G1 从整体上看采用的是标记-整理法,局部(两个 Region)上看是基于复制算法实现的,两个算法都不会产生内存碎片,收集后提供规整的可用内存,这样有利于程序的长时间运行。
  2. 在 STW 上建立了可预测的停顿时间模型,用户可以指定期望停顿时间,G1 会将停顿时间控制在用户设定的停顿时间以内

G1 收集器的工作步骤如下

  1. 初始标记
  2. 并发标记
  3. 最终标记
  4. 筛选回收
    在这里插入图片描述

jvisualvm 命令

装插件

1、找到新的更新地址 visualvm新访问地址: 进入“Plugins”

​ https://visualvm.github.io/pluginscenters.html

在这里插入图片描述

找到对应自己JDK版本的更新地址

在这里插入图片描述

2、进入jvisualvm的插件管理 “工具” - “插件” 在"设置"中修改url地址为刚才我们在github上找到的对应我们JDK版本的地址

在这里插入图片描述

修改成功后,可用插件即可刷新出来

3、安装VisualGC插件

在这里插入图片描述

4、重启即可看到Visual GC
在这里插入图片描述

注:相应的jdk的bin目录下有的jvisualvm .exe文件

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值