ZGC

诞生原因

Java生态非常强大,但还不够,有些场景仍处于劣势,而ZGC的出现可以让Java语言抢占其他语言的某些特定领域市场。比如

  • 谷歌主导的Android手机系统显示卡顿。
  • 证券交易市场,实时性要求非常高,目前主要是C++主导。
  • 大数据集群如HBase的性能。

特性

  • ZGC(The Z Garbage Collector)为JDK11推出一款低延迟的垃圾回收器。STW即停顿时间低于1ms,且不会随着堆的大小增加而增加。

    • 实现主要原理:全并发处理(仅对GC ROOTS进行遍历时会暂停)
  • 高版本JDK16之后支持16TB级别的堆;

    • 实现主要原理:Region分区管理、染色指针寻址
  • 应用程序吞吐量最多减少15%。

    • 实现主要原理:当生命周期很短的对象分配速率很高的时候,大量对象不会被进行标记收集,会产生大量浮动垃圾从而影响吞吐量,并且堆中可转移对象的空间就会越来越小。
  • 为未来的GC新特性奠定基础。

    • 实现主要原理:染色指针中未被使用预留的18 bits。

内存布局

ZGC采用堆空间分页模型的机制,堆空间分页模型也非常符合Linux Kernel2.6引入的标准大页(huge page)如4KB的处理方式。本质与G1一样,没有分代的概念,ZGC也采用基于Region的堆内存布局,不一样的是ZGC的Region具有动态性:动态创建销毁、动态容量大小。ZGC一共分为三种Region:

  • 小型Region(小页面):容量固定为 2MB,存放小于256KB的对象。
  • 中型Region(中页面):容量固定为 32MB,存放大于256KB小于4MB的对象。
  • 大型Region(大页面):容量为 2*N MB,可以动态变化,每个大Region中只会存放一个大对象,并且不会被重分配(即后文介绍的对象的复制),因为大对象的复制代价高昂。

指针着色技术(Color Pointers)

  • ZGC只支持64位的系统,也即是64位的指针。
  • ZGC在JDK11的ZGC来分析中低42位即2的42次方来表示使用中的堆空间,也即是可管理的内存,而在JDK更高版本有所变化。
  • ZGC借助几位高位来做GC相关的事情比如快速实现垃圾回收的并发标记、转移和重定位等。
  • 预留用来给未来的GC新特性预留的扩展点

一段C程序mapping.c看下ZGC的64位虚拟地址空间的指针着色技术展示

编译执行,三个地址一样,也即是同一个实地址映射到3个虚地址。

整体流程

概述

主要分为两步

  • 标记阶段(标记垃圾)
  • 转移阶段(对象复制或移动)

垃圾标记

垃圾标记算法采用可达性分析算法

  • Remapped

    • GC前所有内存都是Remapped,或者标记后如果还是Remapped则是垃圾。
  • M0,发生两次GC为例,M0是1次GC。
    • 前一次GC的标记阶段被标记过的活跃对象,但是上次GC未对对象进行转移。
  • M1,发生两次GC为例,M0是2次GC。
    • 本次垃圾回收中识别的活跃对象。

标记阶段,对象分配(Remapped)

  • 初始标记(标记根)
  • 并发标记(标记剩余)
  • 再标记(解决漏标)

标记结束后Remapped对象即为垃圾对象。而下次标记使用M1表示活跃。

ZGC转移

  • 如果是同一个页面则等同于标记整理。
  • 如果是不同页面等同于复制算法。

JVM调优概述

背景

  • 生产环境中的问题

    • 生产环境中的问题。
    • 生产环境发生了内存溢出该如何处理?
    • 生产环境应该给服务器分配多少内存合适?
    • 如何对垃圾回收器的性能进行调优?
    • 生产环境 CPU 负载飙高该如何处理?
    • 生产环境应该给应用分配多少线程合适?
    • 不加 log,如何确定请求是否执行了某一行代码?
    • 不加 log,如何实时查看某个方法的入参与返回值?
  • 为什么要调优

    • 防止出现 OOM
    • 解决 OOM
    • 减少 Full GC 出现的频率
  • 调优场景

    • Full GC 次数频繁。
    • GC 停顿时间过长(超过1秒)。
    • 应用出现OutOfMemory 等内存异常。
    • 系统吞吐量与响应性能不高或下降
  • 不同阶段的考虑

    • 上线前
    • 项目运行阶段
    • 线上出现 OOM

调优概述

  • 监控的依据

    • 运行日志
    • 异常堆栈
    • GC 日志
    • 线程快照
    • 堆转储快照
  • 调优的大方向
    • 合理地编写代码
    • 充分并合理的使用硬件资源
    • 合理地进行 JVM 调优

调优目标

JVM调优目标是使用较小的内存占用来获得较高的吞吐量或者较低的延迟,从这里也可以知道其重要指标有三个:

  • 内存占用:程序正常运行需要的内存大小。
  • 延迟:由于垃圾收集而引起的程序停顿时间。
  • 吞吐量:用户程序运行时间占用户程序和垃圾收集占用总时间的比值。

从上面我们也知道这三者如同分布式CAP理论一样不可完全兼得,对于一个Java程序同时保证内存占用小、延迟低、高吞吐量是不可能的;任何一个指标性能的提高,几乎都是以牺牲其他指标性能的损为代价的,不可兼得。程序的目标不同,调优时所考虑的方向也不同,因此需要结合实际场景,有明确的优化目标,找到性能瓶颈,对瓶颈有针对性的优化。

调优原则

  • 90%也即是大多数的Java应用不需要进行JVM优化。
  • 大多数导致GC问题的原因是代码层面的问题导致的(代码层面)。
  • 上线之前,应先考虑将机器的JVM参数设置到最优。
  • 减少创建对象的数量,减少使用全局变量和大对象(代码层面)。
  • 优先架构调优和代码调优,JVM优化是不得已的手段。
  • 分析GC情况优化代码比优化JVM参数更好。

调优步骤

  • 第 1 步:性能监控

    • GC 频繁
    • cpu load 过高(如top -hP 进程号;top -d 2 -c等)
    • OOM
    • 内存泄露
    • 死锁
    • 程序响应时间较长
  • 第 2 步:性能分析
    • 打印 GC 日志,通过 GCviewer 或者 gceasy来分析异常信息
    • 灵活运用命令行工具、jstack、jmap、jinfo 等
    • dump 出堆文件,使用内存分析工具分析文件
    • 使用阿里 Arthas、jconsole、JVisualVM 来实时查看 JVM 状态
    • jstack 查看堆栈信息
  • 第 3 步:性能调优
    • 适当增加内存,根据业务背景选择垃圾回收器
    • 优化代码,控制内存使用
    • 增加机器,分散节点压力
    • 合理设置线程池线程数量
    • 使用中间件提高程序效率,比如缓存、消息队列等

性能评价/测试指标

  • 停顿时间(或响应时间)

    • 提交请求和返回该请求的响应之间使用的时间,一般比较关注平均响应时间。

      • 数据库查询一条记录(有索引),十几毫秒。
      • 机械磁盘一次寻址定位。4毫秒
      • 从机械磁盘顺序读取 1M 数据。2毫秒
      • 从 SSD 磁盘顺序读取 1M 数据。0.3毫秒
      • 从内存读取 1M 数据。十几微妙
      • Java程序本地方法调用。几微妙
      • 网络传输2Kb数据。1微妙
  • 吞吐量
    • 对单位时间内完成的工作量(请求)的量度
    • 在 GC 中:运行用户代码的事件占总运行时间的比例(总运行时间:程序的运行时间+内存回收的时间)
    • 吞吐量为 1-1/(1+n),其中-XX::GCTimeRatio=n
  • 内存占用
    • Java 堆区所占的内存大小
  • 相互间的关系
    • 以高速公路通行状况为例
    • 吞吐量:每天通过高速公路收费站的车辆的数据
    • 并发数:高速公路上正在行驶的车辆的数目
    • 响应时间:车速

JVM监控及诊断命令行工具

无监控、不调优!命令行安装 jdk 的 bin 目录,这些工具用来获取目标 JVM 不同方面、不同层次的信息,帮助开发人员很好地解决 Java 应用程序的一些疑难杂症。

  • 查看正在运行的Java进程:jps

    • jps(Java Process Status):显示指定系统内所有的 HotSpot 虚拟机进程(查看虚拟机进程信息),可用于查询正在运行的虚拟机进程。
    • 对于本地虚拟机进程来说,进程的本地虚拟机 ID 与操作系统的进程 ID 是一致的,是唯一的。
    • 基本使用语法为:jps [options] [hostid]
  • 查看JVM统计信息:jstat
    • jstat(JVM Statistics Monitoring Tool):用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据。在没有 GUI 图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。常用于检测垃圾回收问题以及内存泄漏问题。(一般生产环境没gui工具,简单可常用这个)
    • 基本使用语法为:jstat - [-t] [-h] [ []],比如jstat -gc 进程id 1000 10
    • jstat 还可以用来判断是否出现内存泄漏
      • 在长时间运行的 Java 程序中,我们可以运行 jstat 命令连续获取多行性能数据,并取这几行数据中 OU 列(即已占用的老年代内存)的最小值。
      • 然后,我们每隔一段较长的时间重复一次上述操作,来获得多组 OU 最小值。如果这些值呈上涨趋势,则说明该 Java 程序的老年代内存已使用量在不断上涨,这意味着无法回收的对象在不断增加,因此很有可能存在内存泄漏。
  • 实时查看和修改JVM配置参数:jinfo
    • jinfo(Configuration Info for Java):查看虚拟机配置参数信息,也可用于调整虚拟机的配置参数
    • 基本使用语法为:jinfo [options] pid,比如jinfo -sysprops 进程id
  • 导出内存映像文件&内存使用情况:jmap
    • 获取 dump 文件(堆转储快照文件,二进制文件),它还可以获取目标 Java 进程的内存相关信息,包括 Java 堆各区域的使用情况、堆中对象的统计信息、类加载信息等。
    • 基本使用语法为:
      • jmap [option]
      • jmap [option] <executable
      • jmap [option] [server_id@]
    • 使用1:导出内存映像文件
      • 手动的方式
      • jmap -dump:format=b,file=<filename.hprof>
      • jmap -dump:live,format=b,file=<filename.hprof>
    • 使用2:显示堆内存相关信息
      • jmap -heap 进程id
      • jmap -histo 进程id
    • 使用3:其他作用
      • jmap -permstat 进程id
      • 查看系统的ClassLoader信息
      • jmap -finalizerinfo
      • 查看堆积在finalizer队列中的对象
  • JDK 自带堆分析工具:jhat
    • jhat(JVM Heap Analysis Tool):Sun JDK 提供的 jhat 命令与 jmap 命令搭配使用,用于分析 jmap 生成的 heap dump 文件(堆转储快照)。jhat 内置了一个微型的 HTTP/HTML 服务器,生成 dump 文件的分析结果后,用户可以在浏览器中查看分析结果(分析虚拟机转储快照信息)。
    • 使用了 jhat 命令,就启动了一个 http 服务,端口是 7000,即 http://localhost:7000/,就可以在浏览器里分析。
    • 说明:jhat 命令在 JDK9、JDK10 中已经被删除,官方建议用 VisualVM 代替。
    • 基本适用语法:jhat
  • 打印JVM中线程快照:jstack
    • jstack(JVM Stack Trace):用于生成虚拟机指定进程当前时刻的线程快照(虚拟机堆栈跟踪)。线程快照就是当前虚拟机内指定进程的每一条线程正在执行的方法堆栈的集合。
    • 生成线程快照的作用:可用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。这些都是导致线程长时间停顿的常见原因。当线程出现停顿时,就可以用 jstack 显示各个线程调用的堆栈情况。
    • 基本语法 : jstack [option] pid
  • 多功能命令行:jcmd
    • 在 JDK 1.7 以后,新增了一个命令行工具 jcmd。它是一个多功能的工具,可以用来实现前面除了 jstat 之外所有命令的功能。比如:用它来导出堆、内存使用、查看 Java 进程、导出线程信息、执行 GC、JVM 运行时间等。
    • jcmd -l:列出所有的 JVM 进程
    • jcmd pid help:针对指定的进程,列出支持的所有具体命令
    • jcmd pid 具体命令:显示指定进程的指令命令的数据
  • 远程主机信息收集:jstatd
    • 之前的指令只涉及到监控本机的 Java 应用程序,而在这些工具中,一些监控工具也支持对远程计算机的监控(如 jps、jstat)。为了启用远程监控,则需要配合使用 jstatd 工具。命令 jstatd 是一个 RMI 服务端程序,它的作用相当于代理服务器,建立本地计算机与远程监控工具的通信。jstatd 服务器将本机的 Java 应用程序信息传递到远程计算机。

JVM监控及诊断工具GUI

前面我们学习Arthas也是一种JVM监控及诊断工具GUI,本篇先抛出影子,后续在单独针对

  • JDK自带的工具

    • jconsole:JDK 自带的可视化监控工具。查看 Java 应用程序的运行概况、监控堆信息、永久区(或元空间)使用情况、类加载情况等。

      • 从 Java5 开始,在 JDK 中自带的 java 监控和管理控制台。用于对 JVM 中内存、线程和类等的监控,是一个基于 JMX(java management extensions)的 GUI 性能监控工具。
    • Visual VM:Visual VM 是一个工具,它提供了一个可视界面,用于查看 Java 虚拟机上运行的基于 Java 技术的应用程序的详细信息。
      • VisualVM是–个功能强大的多合一故障诊断和性能监控的可视化工具。
      • 它集成了多个JDK命令行工具,使用VisualVM可用于显示虚拟机进程及进程的配置和环境信息(jps ,jinfo),监视应用程序的CPU、GC、堆、方法区及线程的信息(jstat、jstack)等,替JConsole。
      • 在JDK 6 Update 7以后,Visual VM便作为JDK的一 部分发布(VisualVM 在JDK/bin目录下)。此外,Visual VM也可以作为独立的软件安装。
    • JMC:Java Mission Control,内置 Java Flight Recorder。能够以极低的性能开销收集 Java 虚拟机的性能数据。
  • 第三方工具
    • MAT:MAT(Memory Analyzer Tool)是基于 Eclipse 的内存分析工具,是一个快速、功能丰富的 Java heap 分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。

      • MAT 不是一个万能工具,它并不能处理所有类型的堆存储文件。但是比较主流的厂家和格式,例如 Sun,HP,SAP 所采用的 HPROF 二进制堆存储文件,以及 IBM 的 PHD 堆存储文件等都能被很好的解析。
      • 最吸引人的还是能够快速为开发人员生成内存泄漏报表,方便定位问题和分析问题。虽然 MAT 有如此强大的功能,但是内存分析也没有简单到一键完成的程度,很多内存问题还是需要我们从 MAT 展现给我们的信息当中通过经验和直觉来判断才能发现。
    • JProfiler:商业软件,需要付费。功能强大。
    • Flame Graphs(火焰图),在追求极致性能的场景下,了解你的程序运行过程中 cpu 在干什么很重要,火焰图就是一种非常直观的展示 CPU 在程序整个生命周期过程中时间分配的工具和调用找中的 CPU 消耗瓶颈。

此外针对JVM运行时参数和分析GC日志再单独增加专题文档

**本人博客网站 **IT小神 www.itxiaoshen.com

JVM性能调优与实战进阶篇-上的更多相关文章

  1. JVM性能调优与实战基础理论篇-上

    Java虚拟机 概述 Java官方文档 https://docs.oracle.com/en/java/index.html JVM是一种规范,通过Oracle Java 官方文档找到JVM的规范查阅 ...

  2. JVM性能调优与实战基础理论篇-中

    JVM内存模型 概述 我们所说的JVM内存模型是指运行时数据区,用New出来的对象放在堆中,如每个线程中局部变量放在栈或叫虚拟机栈中,下图左边区域部分为栈内存的结构.如main线程包含程序炯酸器.线程 ...

  3. JVM性能调优与实战基础理论篇-下

    JVM内存管理 JVM内存分配与回收策略 对象优先在Eden分配,如果Eden内存空间不足,就会发生Minor GC.虚拟机提供了-XX:+PrintGCDetails这个收集器日志参数,告诉虚拟机在 ...

  4. JVM 性能调优实战之:使用阿里开源工具 TProfiler 在海量业务代码中精确定位性能代码

    本文是<JVM 性能调优实战之:一次系统性能瓶颈的寻找过程> 的后续篇,该篇介绍了如何使用 JDK 自身提供的工具进行 JVM 调优将 TPS 由 2.5 提升到 20 (提升了 7 倍) ...

  5. JVM 性能调优实战之:一次系统性能瓶颈的寻找过程

    玩过性能优化的朋友都清楚,性能优化的关键并不在于怎么进行优化,而在于怎么找到当前系统的性能瓶颈.性能优化分为好几个层次,比如系统层次.算法层次.代码层次…JVM 的性能优化被认为是底层优化,门槛较高, ...

  6. JVM性能调优实践——JVM篇

    前言 在遇到实际性能问题时,除了关注系统性能指标.还要结合应用程序的系统的日志.堆栈信息.GClog.threaddump等数据进行问题分析和定位.关于性能指标分析可以参考前一篇JVM性能调优实践-- ...

  7. 【JAVA进阶架构师指南】之五:JVM性能调优

    前言   首先给大家说声对不起,最近属实太忙了,白天上班,晚上加班,回家还要收拾家里,基本每天做完所有事儿都是凌晨一两点了,没有精力再搞其他的了.   好了,进入正题,让我们来聊聊JVM篇最后一个章节 ...

  8. 使用阿里开源工具 TProfiler 在海量业务代码中精确定位性能代码 (jvm性能调优)

    技术交流群:233513714 本文是<JVM 性能调优实战之:一次系统性能瓶颈的寻找过程> 的后续篇,该篇介绍了如何使用 JDK 自身提供的工具进行 JVM 调优将 TPS 由 2.5 ...

  9. JVM性能调优(3) —— 内存分配和垃圾回收调优

    前序文章: JVM性能调优(1) -- JVM内存模型和类加载运行机制 JVM性能调优(2) -- 垃圾回收器和回收策略 一.内存调优的目标 新生代的垃圾回收是比较简单的,Eden区满了无法分配新对象 ...

随机推荐

  1. 2.16图论专题PB

    超神建图技巧合集 CF1368G 每个骨牌变成让空位移动的至多两条有向边,证明图中无环,形成森林. 然后黑白染色,两类森林互不影响.转为每次标记 A 类一棵子树与 B 类一棵子树形成的所有点对. 再转 ...

  2. Android官方文档翻译 七 2.Adding the Action Bar

    Adding the Action Bar 增加一个Action Bar(工具栏) The action bar is one of the most important design element ...

  3. leetcode 51. N皇后 及 52.N皇后 II

    51. N皇后 问题描述 n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. 上图为 8 皇后问题的一种解法. 给定一个整数 n,返回所有不同的 n 皇后 ...

  4. CVE-2021-44228——Log4j2-RCE漏洞复现

    0x00 漏洞介绍 Apache Log4j2是一个Java的日志组件,在特定的版本中由于其启用了lookup功能,从而导致产生远程代码执行漏洞. 影响版本:Apache Log4j2 2.0-bet ...

  5. 2月10日 体温APP开发总结

    1.Java代码 1.user package bean;public class User { private String name; private String riqi; private S ...

  6. 【C++】类-基础知识

    类-基础知识 目录 类-基础知识 1. 语法定义 2. 类的实现 3. 三个基本的函数 3.1 构造函数 功能 形式 调用时机 默认构造函数 3.2 复制构造函数 功能 形式 调用时机 3.3 析构函 ...

  7. 多线程-其他方法-join等

    1 package multithread4; 2 3 /* 4 * toString():返回该线程的字符串表现形式,包括线程名称.优先级和线程组 5 * Thread[Thread-0,5,mai ...

  8. Photoshop如何快速扣取图标

    由于图标往往与背景色区别很大,因此首先使用魔棒工具快速选择出图标 有时候选择出来是图标,有时候是背景色 可以通过选择反向来调节(右键即可) ctrl + J 提取出选择的区域 这时进行等分裁剪即可 点 ...

  9. APC 篇—— APC 执行

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  10. 分子动力学模拟之基于自动微分的LINCS约束

    技术背景 在分子动力学模拟的过程中,考虑到运动过程实际上是遵守牛顿第二定律的.而牛顿第二定律告诉我们,粒子的动力学过程仅跟受到的力场有关系,但是在模拟的过程中,有一些参量我们是不希望他们被更新或者改变 ...