jvm调优

调优原则和原理分析

1.写在前面

对于JVM调优这个话题,可能大部分程序员都听过这个名词。

但是绝大多数程序员,都没有真真实实去干过,都没有真实的实践过。也不懂得如何调优?不知道要调成怎么样?

那今天咋们就对这个话题来展开描述一下,如何进行jvm调优?主要从以下几个方面进行分享:

  • 调优原则和原理分析
  • JVM垃圾常见的收集器
  • JVM调优常见的工具
  • JVM调优常用的参数
  • JVM调优实践

最后分享一个jvm调优的实践案例。希望可以帮助到各位!!!

那今天我们就来分享一下,jvm调优原则和原理分析

废话不多说了,直接上干货啦!!!

2.什么是JVM?

平时我们所说的JVM广义上指的是一种规范。狭义上的是JDK中的JVM虚拟机

JVM的实现是由各个厂商来做的。比如现在流传最广泛的是hotspot。其他实现:

BEA公司: JRocket
IBM j9
zing 号称世界最快jvm
taobao.vm

JVM用什么语言编写的呢?

Java中的JVM有很多实现,不同厂商的JVM使用编程语言有所不同!

HotSpot是C、C++ 与少量汇编

3.JVM调优疑问三连

是否可以把内存空间设置足够大,那么就不需要回收垃圾呢?

哈哈,可能大部分程序员,都有这么想过。

3.1 为什么JVM调优?

单机的并发因为JVM调优了,可以再翻至少一倍!

调优的最终目的都是为了应用程序使用最小的硬件消耗来承载更大的吞吐量。

jvm调优主要是针对垃圾收集器的收集性能优化,减少GC的频率和Full GC的次数,令运行在虚拟机上的应用能够使用更少的内存以及延迟获取更大的吞吐量和减少暂停时间。

哈哈,说到这里可能大部分人就跳出来说:道理谁不懂呀,可是要怎么干呢?

下面展示了一些JVM调优的量化目标参考实例,注意:不同应用的JVM调优量化目标是不一样的。

调优目标:

  • 堆内存使用率 <= 70%;
  • 老年代内存使用率<= 70%;
  • avg pause <= 1秒;
  • Full GC 次数 0 或 avg pause interval >= 24小时 ;
  • 创建更多的线程

3.2 什么时候JVM调优?

遇到以下情况,就需要考虑进行JVM调优:

  1. 系统吞吐量与响应性能不高或下降;
  2. Heap内存(老年代)持续上涨达到设置的最大内存值;
  3. Full GC 次数频繁;
  4. GC 停顿时间过长(超过 1 秒);
  5. 应用出现OutOfMemory 等内存异常;
  6. 应用中有使用本地缓存且占用大量内存空间;

3.3 调优调什么?

JVM调优核心是什么?

内存分配 + 垃圾回收!

  1. 合理使用堆内存
  2. GC高效回收占用的内存的垃圾对象
  3. GC高效释放掉内存空间

疑问:是否可以把内存空间设置足够大,那么就不需要回收垃圾呢?

这个问题背景:JVM回收垃圾时机,当JVM内存占满触发垃圾回收!

不可以原因如下:

  1. 不回收垃圾,内存增长巨快,再大的空间都不够用;10w请求,2gb垃圾对象
  2. 物理层面: 64 位操作系统可以支持非常大的内存,但不是无限
    1. 32位操作系统: 2~32 = 4GB
    2. 64位操作系统: 2~64 =16384PB
  3. 虚拟机层面:不能设置无限大内存
  4. 内存设置既不能太大,也不能太小需要基于业务场景平衡考量:内存空间设置过大,一旦内存空间触发垃圾回收,就会非常危险,寻找这个垃圾非常耗时,由于内存空间足够大,寻找这个垃圾的时候,极其的消耗时间,因此导致程序停顿;

举个栗子类比一下:房子足够大,是不是就可以不用打扫卫生!显然是不行的


以上就是JVM调优的三大疑问,是不是很多小伙伴,都有这样的疑问呢?

哈哈,估计大伙,多多少少都会带有这样的疑问。

4 调优原则:

  • 优先原则:优先架构调优和代码调优,JVM优化是不得已的手段
    • 大多数的Java应用不需要进行JVM优化
  • 观测性原则:发现问题解决问题,没有问题不找问题

调优,还是得从实际出发,可能咋们写的代码,需要优化,或者我们的框架需要优化。

调优,是不得已的手段了。

5.调优基础知识

在讲JVM调优之前,先简单回顾下JVM相关的基础知识,这里我们重点回顾下JAVA堆、垃圾回收器。这两块也是在JVM调优过程中重点关注的部分。

5.1 堆Heap

被所有线程共享,在虚拟机启动时创建,用来存放对象实例,几乎所有的对象实例都在这里分配内存。

对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。

Java堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC堆”。如果从内存回收的角度看,由于现在收集器基本都是采用的分代收集算法,所以Java堆中还可以细分为:新生代和老年代;

新生代又有Eden空间、From Survivor空间、To Survivor空间三部分。Java 堆不需要连续内存,并且可以通过动态增加其内存,增加失败会抛出 OutOfMemoryError 异常。

5.2 垃圾回收

从年轻代空间(包括 Eden 和 Survivor 区域)被称为 Minor GC

Full GC 是清理整个堆空间—包括年轻代和老年代。

我们不用去关心到底是叫 Minor GC 还是 Full GC,大家应该关注当前的 GC 是否停止了所有应用程序的线程,还是能够并发的处理而不用停掉应用程序的线程,停止了所有应用程序的线程俗称STW。(Stop-the-world )

在 JVM 中,垃圾回收器的具体实现有:

  1. 串行收集器(Serial)
  2. 新生代并行收集器(ParNew)
  3. 并行回收(Parallel Scavenge)
  4. CMS(Concurrent Mark Sweep)
  5. Serial Old(Serial收集器的老年代版本)
  6. Parallel Old(Parallel Scavenge收集器的老年代版本)
  7. G1(Garbage-First)当今收集器技术发展的最前沿成果之一

JVM调优-GC基本原理和调优关键分析

1.写在前面

前面分享了JVM调优原则和原理分析,详情可查看:这里

基于该文章,我们大体上对JVM有一个概况性的理解,同时我们知道了JVM调优原则(JVM优化是不得已的手段)

调优基础知识(head堆,垃圾回收器)等知识点,有一个初步的认识。

那今天我们继续分享一下:垃圾回收算法,和调优的关键指标,等内容。

image.png

2.JVM的GC基本原理

2.1 什么是垃圾?

在内存中没有被引用的对象就是垃圾(一次请求会在内存中创建出很多的对象,这些对象不会自己消失,必须进行垃圾回收,当然垃圾回收器是jvm自己提供的。)

(特别注意:高并发的场景下,内存中尤其会创建海量的对象,这些对象所占用的内存必须及时被释放,否则影响程序性能)

一个对象引用消失了,那么这个对象就变成垃圾;因此这个对象必须被垃圾回收器回收;

image.png

那说到这里,我们就会有疑问了,怎样判断一个对象,将会成为垃圾呢?

别急,且听哥们一一道来!!!接着往下。

2.2 如何找到这个垃圾?

Jvm中有 2 种寻找垃圾对象的方案:

1 、引用计数算法

2 、根可达算法 ----- hotspot垃圾回收器都是使用这个算法

1) 引用计数算法:

通过引用计数方法,找到这个垃圾:

image.png

当这个对象引用都消失了,消失一个计数减一,当引用都消失了,计数就会变为0.此时这个对象就会变成垃圾。

这样,会存在问题:

在堆内存中主要的引用关系有如下三种:

  • 单一引用
  • 循环引用
  • 无引用
image.png

由此可见,引用计数算法不能解决循环引用问题。为了解决这个问题,Java使用了根可达分析算法。

循环引用,使用这个算法,是无法解决的。

那就引出了另外一种算法:根可达算法

2) 根可达算法:

hotspot 目前使用的主要的垃圾回收器的算法,因为引用计数无法解决循环引用计数的问题。

根可达分析算法的基本思想是: 通过一系列名为"GC roots"的对象作为起始点,从这个被称为GC roots的对象开始,向下搜索,如果一个对象到GC roots没有任何引用链相连时,说明此对象不可用。

也即给定一个集合的引用作为出发,通过引用关系遍历对象图,能够遍历到的(可到达)对象就被判定为存活,没有则自然被判定为死亡

所谓的"GC roots"对象起始点,或者说tracing GC的"根集合"就是一组必须活跃的引用。

通过根可达算法,我们已经找出垃圾对象了,接下来,就是清除垃圾。

如何清除垃圾呢?这里JVM提供3种算法。且听哥们一一道来!!!

image.png

2.3 如何清除垃圾?

JVM提供 3 种方法,清除垃圾对象

  1. Mark-Sweep 标记清除算法
  2. Copying 拷贝算法
  3. Mark-Compact 标记压缩算法

Mark-Sweep 标记清除算法

image.png
  • 缺点:内存存储空间碎片化

Copying 拷贝算法

为了解决效率问题,Copying 拷贝算法将可用内存按容量划分为大小相等的两块,每次只使用其中一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一半。

  • 优点:没有碎片化,所有的有用的空间都连接在一起,所有的空闲空间都连接在一起
  • 缺点:存在空间浪费。

Mark-Compact 标记压缩算法

image.png

标记压缩算法,把存活对象拷贝到可回收的空间,然后把存活对象空间进行压缩,串联起来,把未使用的对象空间串联起来,组成连续的内存空间,这样就不会有碎片。

  • 缺点:性能较低,因为除了拷贝对象以外,还需要对象内存空间进行压缩,所以性能较低。

2.4 用什么清除垃圾

有 7 种不同的垃圾回收器,它们分别用于不同分代的垃圾回收。

  • 新生代回收器:Serial、ParNew、Parallel Scavenge
  • 老年代回收器:Serial Old、Parallel Old、CMS
  • 整堆回收器:G

两个垃圾回收器之间有连线表示它们可以搭配使用,可选的搭配方案如下:

新生代 老年代
Serial Serial Old
Serial CMS
ParNew Serial Old
ParNew CMS
Parallel Scavenge Serial Old
Parallel Scavenge Parallel Old
G1 G1

3.调优关键指标

调优的最终目的都是为了应用程序使用 最小的硬件 消耗来承载更大的 吞吐量

3.1 吞吐量

重要指标之一,吞吐量是衡量系统在单位时间里面完成的工作数量。吞吐量需求通常忽略延迟或者响应时间。通常情况下,提升吞吐量需要以系统响应变慢和更多内存消耗作为代价。

  • TPS:每秒事务数
  • Throughput:吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间),虚拟机总共运行了 100 分钟,其中垃圾收集花掉 1 分钟,那吞吐量就是99%。

3.2 延迟或响应时间

延迟或者响应时间是衡量应用从接收到一个任务到完成这个任务消耗的时间。一个延迟或者响应时间的需求需要忽略吞吐量。通常来讲,提升应用的响应时间需要以更低吞吐量或提高应用的内存消耗。

延迟或者响应时间例子:"例如系统处理一个HTTP请求需要200ms,这个200ms就是系统的响应时间。"

3.3 内存占用

内存占用是衡量应用消耗的内存,这个内存占用是指应用在运行在某一个吞吐量、延迟以及可用性和易管理性指标下的内存消耗,内存占用是通常描述为应用运行的时候Java堆的大小或者总共需要消耗内存。

通常情况下,通过增加Java堆的大小以增加应用内存占用可以提升吞吐量或者减少延迟,或者两者兼具。当应用可用的内存减少的时候,吞吐量和延迟通常会受到损失。在给定内存的情况下,应用占用的内存可以限制应用的实例数(这个会影响可用性)。

内存占用需求例子:“这个应用会单独运行在一个8G的系统上面或者多出 3 个应用实例运行在一个24G的应用系统上面。

JVM调优-常见的垃圾回收器

1.写在前面

前面分享了GC基本原理和调优关键分析,详情可查看:这里

基于该文章,我们了解了,如何找到垃圾如何使用垃圾回收器清除垃圾

我们之前已经给出了有 7 种不同的垃圾回收器,大概的讲了一下,这些垃圾回收器的搭配,对应于那个年代(老年代、新生代) 的垃圾回收。

那今天我们继续详细的分享一下:JVM垃圾收集器

这些垃圾回收器,具体的一些原理。

好了,废话不多说,直接上干货。(纯理论比较多,大家伙耐心点看)

image.png

哈哈,绝对有收获,没收获的轻点喷!!!_

新生代 老年代
Serial Serial Old
Serial CMS
ParNew Serial Old
ParNew CMS
Parallel Scavenge Serial Old
Parallel Scavenge Parallel Old
G1 G1

这里先贴一下,常见的垃圾回收器。

2.JVM垃圾收集器

2.1.串行收集器(Serial)

2.1.1 基本概念

使用单线程进行垃圾回收的收集器,每次回收时,串行收集器只有一个工作线程,对于并行能力较弱的计算机来说,串行收集器的专注性和独占性往往有更好的性能表现。

串行收集器可以在新生代老年代中使用,根据作用于不同的堆空间,分为新生代串行收集器和老年代收集器。

配置参数 -XX:+UseSerialGC :年轻串行(Serial),老年串行(Serial Old

2.1.2 Serial收集器:年轻串行

Serial收集器是一个新生代收集器,单线程执行,使用复制算法。它在进行垃圾收集时,必须暂停其他所有的工作线程(用户线程)。是JVM Client模式下默认的新生代收集器。对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率

image.png

这里说的复制算法,大家伙,还有记得不?

就是我们上一篇说得的三种垃圾清除算法

哈哈,估计都忘了吧?这里,咋们再回顾一下

  1. Mark-Sweep 标记清除算法
  2. Copying 拷贝算法
  3. Mark-Compact 标记压缩算法

image.png

2.1.3 Serial Old收集器:老年串行

  • Serial收集器的老年代版本,它同样是一个单线程收集器,使用 “标记-整理”算法
  • 主要意义也是在于给Client模式下的虚拟机使用。

image.png

这里,解析一下什么是safe point?

挂起线程的点

  • 从全局观点来看,所有线程必须在GC 运行前,在一个safepoint处阻塞(block)。
  • 从局部观点来看,safepoint是一个代码块中特殊的一点,该处正在执行的线程可以因GC而阻塞。
  • GC的标记阶段需要stop the world,让所有Java线程挂起,这样JVM才可以安全地来标记对象。

safepoint可以用来实现让所有Java线程挂起的需求。这是一种 "主动式"(Voluntary Suspension)的实现

safe point指的特定位置主要有:

  1. 循环的末尾 (防止大循环的时候一直不进入safepoint,而其他线程在等待它进入safepoint)
  2. 方法返回前
  3. 调用方法的call之后
  4. 抛出异常的位置

image.png

以上的两种,就是串行的垃圾收集器了,下面继续分析并行的垃圾收集器

image.png

2.2. 并行收集器

2.2.1 Parallel Scavenge收集器

配置参数:-XX:+UseParallelGC

目标是达到一个可控制的吞吐量(Throughput)。

吞吐量 = 运行用户代码时间 /(运行用户代码时间+垃圾收集时间)。

虚拟机总共运行了 100 分钟,其中垃圾收集花掉 1 分钟,那吞吐量就是99%。

image.png

特点:

  • 新生代使用并行回收收集器,老年代使用串行收集器
  • 吞吐量优先收集器
  • 新生代收集器复制算法,是并行的多线程收集器。

image.png

这里,有必要,解析一下什么是并发,什么是并行?

  • 并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待态。
  • 并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。

答应我,别再傻傻分不清楚了!

2.2.2 Parallel Old收集器

配置参数:-XX:+UseParallelOldGC

特点:

  • Parallel Scavenge收集器的老年代版本,使用多线程和 “标记-整理”算法
  • 在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel ScavengeParallel Old收集器。

image.png

2.2.3 ParNew收集器

配置参数:-XX:+UseParNewGC

配置参数:-XX:ParallelGCThreads=n 设置并行收集器收集时使用的并行收集线程数。一般最好和计算机的CPU相当

特点:

  • 新生代并行(ParNew),老年代串行(Serial Old)
  • Serial收集器的多线程版本
  • 单CPU性能并不如Serial,因为存在线程交互的开销

image.png

image.png

2.2.4 CMS收集器

配置参数:-XX:+UseConcMarkSweepGC 应用CMS收集器。

尽管CMS收集器采用的是 并发回收(非独占式) ,但是在其初始标记重新标记这两个阶段中仍然需要执行“Stop-the-World”机制暂停程序中的工作线程,不过暂停时间并不会太长。

因此可以说明 目前所有的垃圾收集器都做不到完全不需要“stop-the-World只是尽可能地缩短暂停时间

由于最耗费时间的并发标记并发清除阶段都不需要暂停工作,所以整体的回收是低停顿的。

另外,由于在垃圾收集阶段用户线程没有中断 ,所以在CMS回收过程中,还应该确保应用程序用户线程有足够的内存可用。

特点:

  • 低延迟: 减少STW对用户体验的影响【响应时间和延迟要求高】
  • 并发收集:可以同时执行用户线程
  • CMS收集器 不能像其他收集器那样等到老年代几乎完全被填满了再进行收集 ,而是当堆内存使用率达到某一阈值时,便开始进行回收。
  • CMS收集器的垃圾收集算法采用的是标记清除算法。
  • 会产生内存碎片,导致并发清除后,用户线程可用的空间不足。
  • CMS收集器对CPU资源非常敏感。

CMS垃圾回收器:

CMS整个过程比之前的收集器要复杂,整个过程分为 4 个主要阶段,即初始标记阶段并发标记阶段重新标记阶段并发清除阶段

( 涉及STW的阶段主要是:初始标记重新标记 )

  • 初始标记(Initial-Mark)阶段 :在这个阶段中,程序中所有的工作线程都将会因为“stop-the-world”机制而出现短暂的暂停,这个阶段的主要任务仅仅只是标记出GCRoots能直接关联到的对象。一旦标记完成之后就会恢复之前被暂停的所有应用线程。由于直接关联对象比较小,所以这里的速度非常快。【STW】
  • 并发标记(Concurrent-Mark)阶段 :从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行。
  • 重新标记(Remark)阶段 :由于在并发标记阶段中,程序的工作线程会和垃圾收集线程同时运行或者交叉运行,因此为了 修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录 ,这个阶段的停顿时间通常会比初始标记阶段稍长一些,但也远比并发标记阶段的时间短。【STW】
  • 并发清除(Concurrent-Sweep)阶段 :此阶段清理删除掉标记阶段判断的已经死亡的对象,释放内存空间。由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。

好吧,有点长了,坚持一下,快完了!!!

image.png

2.2.5 G1(Garbage-First)收集器

配置参数:-XX:+UseG1Gc 应用G1收集器

配置参数:-XX:MaxGCPauseMillis 指定最大停顿时间

配置参数:-XX:ParallelGCThreads 设置并行回收的线程数量

Garbage-First当今收集器技术发展的最前沿成果之一,G1是一款面向服务端应用的垃圾收集器。大内存,企业配置的垃圾收集器大多都是G1。

特点:

  1. 并行与并发:充分利用多CPU、多核环境下的硬件优势
  2. 分代收集:不需要其他收集器配合就能独立管理整个GC堆
  3. 空间整合:“标记—整理”算法实现的收集器,局部上基于“复制”算法不会产生内存空间碎片
  4. 可预测的停顿:能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒

image.png

G1收集器的运作大致可划分为以下几个步骤:

  1. 初始标记:标记一下GC Roots能直接关联到的对象,需要停顿线程,但耗时很短
  2. 并发标记:是从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执行
  3. 最终标记:修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录
  4. 筛选回收:对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划

好了,以上就是并行收集器的描述了。

哈哈,可能有点长,耐心点看吧!!!

总结

在众多的垃圾回收器中,没有最好的,只有最适合应用的回收器,根据应用软件的特性以及硬件平台的特点,选择不同的垃圾回收器,才能有效的提高系统性能。

JVM调优-常见的调优工具

1.写在前面

前面分享了常见的垃圾回收器,详情可查看:这里

基于该文章,我们了解了,7种不同的垃圾回收器以及这些垃圾回收器底层是使用了什么算法,和它们的一些特点,运行机制等内容。

对于老年代,新生代之间,垃圾回收器是如何搭配使用的,这个话题,我们也给出了详细的说明。

既然,已经掌握了这些,那我们可以继续往下深入学习。例如:如何进行jvm调优?

在进行jvm调优前,那我们就得掌握一些jvm调优的一些工具!!!_

好,那今天我们继续的分享一下:常见的调优工具

好了,废话不多说,直接上干货。

image.png

2.Minor GC 、Major GC和 Full GC 有什么区别?

在分享JVM调优工具前,我们先来谈谈gc的一些知识点。

  • 新生代收集(Minor GC/Young GC):指目标只是新生代的垃圾收集。Minor GC 非常频繁,回收速度比较快。
  • 老年代收集(Major GC/Old GC):指目标只是老年代的垃圾收集, Major GC 一般比 Minor GC慢 10 倍以上。目前只有CMS收集器会有单独收集老年代的行为。
  • 整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集。
  • 混合收集(Mixed GC):指目标是收集整个新生代以及部分老年代的垃圾收集。目前只有G1收集器会有这种行为。

image.png

3.JVM调优工具

3.1 JDK工具包

3.1.1 jps

jps:Java Virtual Machine Process Status Tool

查看Java进程 ,相当于Linux下的ps命令,只不过它只列出Java进程。

jps :列出Java程序进程ID和Main函数名称
jps -q :只输出进程ID
jps -m :输出传递给Java进程(主函数)的参数
jps -l :输出主函数的完整路径
jps -v :显示传递给Java虚拟的参数
复制代码

image.png

可以jps -l看到,打印出我们的主函数类

3.1.2 jstat

jstat:JVM Statistics Monitoring Tool

jstat可以查看Java程序运行时相关信息,可以通过它查看堆信息的相关情况

jstat -<options> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
复制代码
options:由以下值构成
-class:显示ClassLoader的相关信息
-compiler:显示JIT编译的相关信息
-gc:显示与GC相关信息
-gccapacity:显示各个代的容量和使用情况
-gccause:显示垃圾收集相关信息(同-gcutil),同时显示最后一次或当前正在发生的垃圾收集的诱发原因
-gcnew:显示新生代信息
-gcnewcapacity:显示新生代大小和使用情况
-gcold:显示老年代信息
-gcoldcapacity:显示老年代大小
-gcpermcapacity:显示永久代大小
-gcutil:显示垃圾收集信息
复制代码

示例:

jstat -gcutil pid 5s 5
# 5s每隔 5 秒采样一次
# 5采样五次
复制代码

image.png

S0  年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1  年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E   年轻代中Eden(伊甸园)已使用的占当前容量百分比
O   old代已使用的占当前容量百分比
M   metaspace已使用的占当前容量百分比
CCS 压缩使用比例
YGC 从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间(s)
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)
复制代码

3.1.3 jinfo

jinfo:Java Configuration Info

jinfo可以用来查看正在运行的java程序的扩展参数,甚至支持运行时,修改部分参数

jinfo [option] <pid>
复制代码
-flags 打印虚拟机 VM 参数
-flag <name> 打印指定虚拟机 VM 参数
-flag [+|-]<name> 打开或关闭虚拟机参数
-flag <name>=<value> 设置指定虚拟机参数的值
复制代码

示例:

image.png

3.1.4 jmap

jmap:Memory Map

jmap用来查看堆内存使用状况,一般结合jhat使用。

参数:

option: 选项参数。
pid: 需要打印配置信息的进程ID。
executable: 产生核心dump的Java可执行文件。
core: 需要打印配置信息的核心文件。
server-id: 可选的唯一id,如果相同的远程主机上运行了多台调试服务器,用此选项参数标识服务器。
remote server IP or hostname 远程调试服务器的IP地址或主机名。

option
no option: 查看进程的内存映像信息,类似 Solaris pmap 命令。
heap: 显示Java堆详细信息
histo[:live]: 显示堆中对象的统计信息
clstats:打印类加载器信息
finalizerinfo: 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象

dump:<dump-options>:生成堆转储快照
F: 当-dump没有响应时,使用-dump或者-histo参数. 在这个模式下,live子参数无效.
help:打印帮助信息
J<flag>:指定传递给运行jmap的JVM的参数

复制代码

示例:heap

命令:jmap -heap pid

描述:显示Java堆详细信息

打印一个堆的摘要信息,包括使用的GC算法、堆配置信息和各内存区域内存使用信息

image.png

哈哈,命令,有点多!!!

记住,这些命令,不需要死记硬背的,用到的时候,面向百度即可!!!

image.png

3.2 VisualVM工具

开发大型 Java 应用程序的过程中难免遇到内存泄露、性能瓶颈等问题,比如文件、网络、数据库的连接未释放,未优化的算法等。

随着应用程序的持续运行,可能会造成整个系统运行效率下降,严重的则会造成系统崩溃。为了找出程序中隐藏的这些问题,在项目开发后期往往会使用性能分析工具来对应用程序的性能进行分析和优化。

VisualVM 是一款免费的性能分析工具。同时,它能自动选择更快更轻量级的技术尽量减少性能分析对应用程序造成的影响,提高性能分析的精度。

一般来说,jdk都会自带该工具,具体的路径,为安装的jdk路径下面。

image.png

直接双击即可打开。

image.png

直接可以监控到java进程,双击打开需要监控的java进程即可。

3.3 MemoryAnalyzer工具

Memory Analyzer (Eclipse MAT)是一个跨平台的开源工具,您不仅可以用它来分析内存问题,也可以用来监控整个 Java 应用程序的状态和行为。通过读取应用程序运行时由 Java 运行时环境生成的转储文件快照,Memory Analyzer 使您能够分析那些调试代码可能无法发现的复杂问题。

这里分享一个下载连接:

链接:https://pan.baidu.com/s/1Cy4owFs8SM6ZgAUDfIy2NA 
提取码:0hly
复制代码

下载后,直接解压即可使用:

image.png

装入heap dump文件

image.png

分析:

image.png

这样就可以分析我们的heap dump文件,快速找到内存泄漏的地方。

3.4 第三方 GCEasy

gceasy.io/

业界首先采用机器学习算法解决GC日志分析问题,GCeasy内置机器智能可以自动检测JVM和Android GC日志中的问题,并推荐解决方案。

GC日志分析是免费的, Machine Learning 收费

  • 几秒内解决GC和内存问题
  • JVM堆优化建议
  • 机器学习算法
posted @   雾霭雾海  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示