当前位置: 首页 > news >正文

JVM 实战篇(一万字)

此笔记来至于 黑马程序员

image-20241011150518298

内存调优

内存溢出和内存泄漏

  • 内存泄漏(memory leak):在Java中如果不再使用一个对象,但是该对象依然在 GC ROOT 的引用链上,这个对象就不会被垃圾回收器回收,这种情况就称之为内存泄漏。
  • 内存泄漏绝大多数情况都是由堆内存泄漏引起的,所以后续没有特别说明则讨论的都是堆内存泄漏。
  • 少量的内存泄漏可以容忍,但是如果发生持续的内存泄漏,就像滚雪球雪球越滚越大,不管有多大的内存迟早会被消耗完,最终导致的结果就是内存溢出。但是产生内存溢出并不是只有内存泄漏这一种原因

image-20241011151333653

image-20241011152029780

  • 内存泄漏导致溢出的常见场景是大型的 Java后端应用 中,在处理用户的请求之后,没有及时将用户的数据删除。随着用户请求数量越来越多,内存泄漏的对象占满了堆内存最终导致内存溢出。
  • 这种产生的内存溢出会直接导致用户请求无法处理,影响用户的正常使用。重启可以恢复应用使用,但是在运行一段时间之后依然会出现内存溢出
  • 第二种常见场景是 分布式任务调度系统如 Elastic-job、Quartz 等进行任务调度时,被调度的 Java应用 在调度任务结束中出现了内存泄漏,最终导致多次调度之后内存溢出。
  • 这种产生的内存溢出会导致应用执行下次的调度任务执行**。同样重启可以恢复应用使用,但是在调度执行一段时间之后依然会出现内存溢出。**

解决内存溢出的方法

image-20241011161821552

发现问题 - Top 命令
  • top命令 是 linux 下用来查看系统信息的一个命令,它提供给我们去实时地去查看系统的资源,比如执行时的进程、线程和系统参数等信息。
  • 进程使用的内存为 RES(常驻内存)- SHR(共享内存)

image-20241011162105848

发现问题 - VisualVM
  • VisualVM是多功能合一的 Java故障排除工具 并且他是一款 可视化工具,整合了 命令行JDK工具 和 轻量级分析功能,功能非常强大。
  • 这款软件在 Oracle JDK 6~8 中发布,但是在 Oracle JDK 9 之后不在JDk安装目录下需要单独下载。
  • 下载地址:https://visualvm.github.io/
云服务器配置

image-20241011164325281

image-20241011164429775

只能用于测试环境,因为会有 STW 影响用户体验

发现问题- Arthas
  • Arthas 是一款线上监控诊断产品,通过全局视角实时查看 应用load、内存、gc、线程 的状态信息,**并能在不修改应用代码的情况下,对业务问题进行诊断,**包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。

image-20241011164706550

image-20241011164912911

发现问题 - Prometheus + Grafana
  • Prometheus + Grafana 是企业中运维常用的监控方案,其中 Prometheus 用来采集系统或者应用的相关数据,同时具备告警功能。Grafana 可以将 Prometheus 采集到的数据以可视化的方式进行展示。
  • Java程序员 要学会如何读懂 Grafana 展示的 Java虚拟机 相关的参数。

image-20241011165939158

image-20241011171029053

发现问题 - 堆内存状况的对比

image-20241011171444574

产生内存溢出原因一:代码中的内存泄漏(压力测试)

image-20241011171534308

equals() 和 hashcode() 导致的内存泄漏

1、以 JDK8 为例,首先调用 hash方法 计算 key 的哈希值,hash方法 中会使用到 key的 hashcode方法。根据 hash方法 的结果决定存放的数组中位置。
2、如果没有元素,直接放入。如果有元素,先 判断key 是否相等,会用到 equals方法,如果 key相等,直接替换value;key不相等,走链表或者红黑树查找逻辑,其中也会使用equals比对是否相同。

1、hashCode 方法实现不正确,会导致相同 id的学生对象计算出来的 hash值 不同,可能会被分到不同的槽中。
2、equals 方法实现不正确,会 导致key在 比对时,即便学生对象的 id是相同的,也被认为是 不同的key。
3、长时间运行之后 HashMap中会 保存大量相同id的学生 数据。

image-20241011174855774

image-20241011172728196

解决方案:

1、在定义新实体时,始终重写 equals() 和 hashCode() 方法。
2、重写时一定要确定使用了唯一标识去区分不同的对象,比如用户的id等。
3、hashmap 使用时尽量使用编号 id 等数据作为 key,不要将整个实体类对象作为 key存放。

案例2:内部类引用外部类
  • 1、非静态的内部类默认会持有外部类,尽管代码上不再使用外部类,所以如果有地方引用了这个非静态内部类,会导致外部类也被引用,垃圾回收时无法回收这个外部类。
  • 2、匿名内部类对象如果在非静态方法中被创建,会持有调用者对象,垃圾回收时无法回收调用者。
public class Outer {private byte[] bytes = new byte[1024 * 1024]; // 外部类持有数据private String name = "测试";class Inner { // 改为静态内部类就好了 static class Innerprivate String name;public Inner() {this.name = Outer.this.name;}}public static void main(String[] args) throws IOException, InterruptedException {System.in.read();int count = 0;ArrayList<Inner> inners = new ArrayList<>();while (true) {if (count++ % 100 == 0) {Thread.sleep(10);}inners.add(new Outer().new Inner());}}
}

1、这个案例中,使用内部类的原因是可以直接获取到外部类中的成员变量值,简化开发。如果不想持有外部类对象,应该使用静态内部类。
2、使用静态方法,可以避免匿名内部类持有调用者对象。

案例3:ThreadLocal 的使用

image-20241011185345312

import java.util.concurrent.*;public class Demo5 {public static ThreadLocal<Object> threadLocal = new ThreadLocal<>():public static void main(String[] args) {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(Integer.MAX_VALUE, Integer.MAX_VALUE,keepAliveTime:0,TimeUnit.DAYS, new SynchronousQueue<>());int count = 0;while (true) {System.out.println(++count);threadPlloExecutor.execute(() -> {threadPoolExecutor.set(new byte[1024 * 1024]);// threadLocal.remove();  线程池一定要释放 threadPoolExecutor });}}
}
案例4:String 的 intern 方法

image-20241011190129392

import java.util.ArrayList;
import java.util.List;public class Demo6_2 {public static void main(String[] args) {List<String> list = new ArrayList<String>();int i = 0;while (true) {// String.valueOf(i++).intern(); // JDK1.6 perm gen 不会溢出list.add(String.valueOf(i++).intern()); // 溢出}}
}
案例5:通过静态字段保存对象

image-20241011191401993

import java.time.Duration;public class CaffineDemo {public static void main(String[] args) throws InterruptedException {Cache<Object, Object> build = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(100)).build();int count = 0;while (true) {build.put(count++, new byte[1024 * 1024 * 10]);Thread.sleep(100L);}}
}

image-20241011192007708

产生内存溢出原因二:并发请求问题
  • 并发请求问题指的是用户通过发送请求 向 Java应用 获取数据,正常情况下 Java应用将数据返回之后,这部分数据就可以在内存中被释放掉。

  • 并发请求问题指的是用户通过发送请求向 Java应用获取数据,正常情况下 Java应用 将数据返回之后,这部分数据就可以在内存中被释放掉。**但是由于用户的并发请求量有可能很大,同时处理数据的时间很长,导致大量的数据存在于内存中,最终超过了内存的上限,导致内存溢出。**这类问题的处理思路和内存泄漏类似,首先要定位到对象产生的根源。

image-20241011192945175

使用 Jmeter 进行并发测试,发现内存溢出问题

image-20241011193030224

诊断-内存快照

  • 当堆内存溢出时,需要在堆内存溢出时将整个堆内存保存下来,生成内存快照(HeapProfile)文件

  • 使用 MAT打开 hprof文件,并选择内存泄漏检测功能,MAT 会自行根据内存快照中保存的数据分析内存泄源的根源。

  • 生成内存快照的 Java虚拟机 参数:
    -XX:+HeapDumpOnOutOfMemoryError:发生 OutOfMemoryError 错误时,自动生成 hprof 内存快照文件。
    -XX:HeapDumpPath = :指定 hprof文件 的输出路径。

MAT 内存泄漏检测的原理-支配树
  • MAT 提供了称为 **支配树(DominatorTree)**的对象图。支配树展示的是对象实例间的支配关系。在对象引用图中,所有指向对象B的路径都经过对象A,则认为 对象A 支配 对象B。

image-20241011202742562

MAT 内存泄漏检测的原理-深堆和浅堆

image-20241011211241696

image-20241011211333872

// -XX:+HeapDumpBeforeFullGC -XX:HeapDumpPath=D:/jvm/heapdemo.hprof
public class HeapDemo {public static void main(String[] args) {TestClass a1 = new TestClass();TestClass a2 = new TestClass();TestClass a3 = new TestClass();String s1 = "itheima1";String s2 = "itheima2";String s3 = "itheima3";a1.list.add(s1);a2.list.add(s1);a2.list.add(s2);a3.list.add(s3);// System.out.print(ClassLayout.parseClass(TestClass.class).toPrintable());s1 = null;s2 = null;s3 = null;System.gc();}
}

image-20241011214825207

MAT 内存泄漏检测的原理

image-20241011215329321

导出运行中系统的内存快照并进行分析

image-20241011215756900

分析超大堆的内存快照
  • 在程序员开发用的机器内存范围之内的快照文件,直接使用 MAT 打开分析即可。但是经常会遇到服务器上的程序占用的内存达到 10G以上,开发机无法正常打开此类内存快照,此时需要下载服务器操作系统对应的 MAT。 下载地址: https://eclipse.dev/mat/downloads.php

image-20241011221408384

案例实战

image-20241011221724444

案例1-分页查询文章接口的内存溢出

image-20241011221918900

image-20241011221852061

image-20241011223246327

案例2- Mybatis 导致的内存溢出

image-20241011224532800

案例3 - 导出大文件内存溢出

image-20241011224719174

image-20241011230057521

案例4- ThreadLocal 使用时占用大量内存

image-20241011230854575

image-20241011230823686

案例5-文章内容审核接口的内存问题

image-20241011230935004

image-20241011231121950

存在问题:

1、线程池参数设置不当,会导致大量线程的创建或者队列中保存大量的数据。
2、任务没有持久化,一旦走线程池的拒绝策略或者服务宕机、服务器掉电等情况很有可能会丢失任务。

image-20241011231709485

image-20241011232008891

image-20241011232134014

诊断和解决问题 两种方案

image-20241011232252246

在线定位问题 -步骤

image-20241011232618809

1 在线定位问题 btrace

image-20241011233113483

官网:https://github.com/btraceio/btrace/releases/latest

2、内存溢出有哪几种产生的原因?

1、持续的内存泄漏:内存泄漏持续发生,不可被回收同时不再使用的内存越来越多就像滚雪球雪球越滚越大,最终内存被消耗完无法分配更多的内存取使用,导致内存溢出。
2、并发请求问题:用户通过发送请求向Java应用获取数据,正常情况下Java应用将数据返回之后,这部分数据就可以在内存中被释放掉。但是由于用户的并发请求量有可能很大,同时处理数据的时间很长,导致大量的数据存在于内存中,最终超过了内存的上限,导致内存溢出。

3、解决内存泄漏问题的方法是什么?

1、发现问题,,通过监控工具尽可能尽早地发现内存慢慢变大的现象。
2、诊断原因,通过分析内存快照或者在线分析方法调用过程,诊断问题产生的根源,定位到出现问题的源代码。
3、修复源代码中的问题,如代码bug、技术方案不合理、业务设计不合理等等。
4、在测试环境验证问题是否已经解决,最后发布上线。

GC 调优

GC调优 指的是对**垃圾回收(Garbage Collection)**进行调优。GC调优的主要目标是避免由垃圾回收引起程序性能下降。

GC调优的核心分成三部分:
1、通用 Jvm参数 的设置。
2、特定垃圾回收器的 Jvm参数的设置。
3、解决由频繁的 FULL GC 引起的程序性能问题。

GC调优没有没有唯一的标准答案,如何调优与硬件、程序本身、使用情况均有关系,重点学习调优的工具和方法。

GC调优的核心指标

所以判断 GC 是否需要调优,需要从三方面来考虑,与 GC算法 的评判标准类似:
1.吞吐量(Throughput)吞吐量分为业务吞吐量和垃圾回收吞吐量
业务吞吐量 指的在一段时间内,程序需要完成的业务数量。比如企业中对于吞吐量的要求可能会是这样的:

  • 支持用户每天生成10000笔订单
  • 在晚上8点到10点,支持用户查询50000条商品信息

GC调优 的方法

保证高吞吐量的常规手段有两条:

1、优化业务执行性能,减少单次业务的执行时间
2、优化垃圾回收吞吐量

image-20241011235212818

image-20241011235255462

image-20241011235403878

3.内存使用量

内存使用量指的是 Java应用 占用系统内存的最大值,一般通过 Jvm参数调整,在满足上述两个指标的前提下,这个值越小越好。

image-20241011235513666

发现问题页- jstat 工具
  • Jstat工具 是 JDK 自带的一款监控工具,可以提供各种垃圾回收、类加载、编译信息等不同的数据。
  • 使用方法为:jstat-gc 进程ID 每次统计的间隔 (毫秒) 统计次数

image-20241011235900009

发现问题- visualvm插 件
  • VisualVm 中提供了一款 visualTool 插件,实时监控 Java进程 的堆内存结构,堆内存变化趋势以及垃圾回收时间的变化趋势。同时还可以监控对象晋升的直方图。

image-20241012000022885

Prometheus + Grafana
  • Prometheus + Grafana 是企业中运维常用的监控方案,其中 Prometheus用来采集系统或者应用的相关数据,同时具备告警功能。Grafana 可以将 Prometheus 采集到的数据以可视化的方式进行展示。
  • Java程序员要学会如何读懂 Grafana展示 的 Java虚拟机 相关的参数。

image-20241012000336691

发现问题 -GC 日志
  • 通过 GC日志,可以更好的看到垃圾回收细节上的数据,同时也可以根据每款垃圾回收器的不同特点更好地发现存在的问题。
  • 使用方法(JDK 8及以下):-XX:+PrintGCDetails -Xloggc:文件名
  • 使用方法(JDK 9+):-Xlog:gc*:file=文件名

image-20241012001414831

发现问题 - GC Viewer
  • GC Viewer 是一个将 GC日志 转换成可视化图表的小工具

    github 地址: https://github.com/chewiebug/GcViewer

  • 使用方法:java-jar gcviewer_1.3.4.jar 日志文件.log

image-20241012001703938

发现问题 - GCeasy
  • GCeaSy是业界首款使用 AI机器学习技术 在线进行 GC分析 和 诊断的工具。定位内存泄漏、GC延迟高 的问题,提供 JVM参数优化建议,支持在线的可视化工具图表展示。

    官方网站:https://gceasy.io/

image-20241012002543353

发现问题 - 常见的 GC模式
一、正常情况

特点:呈现锯齿状,对象创建之后内存上升,一旦发生垃圾回收之后下降到底部,并且每次下降之后的内存大小接近,存留的对象较少

image-20241012094955440

二、缓存对象过多

特点:呈现锯齿状,对象创建之后内存上升,一旦发生垃圾回收之后下降到底部,并且每次下降之后的内存大小接近,处于比较高的位置。
问题产生原因:程序中保存了大量的缓存对象,导致 GC 之后无法释放,可以使用 MAT 或者 HeapHero等工具 进行分析内存占用的原因。

image-20241012095108175

三、内存泄漏

特点:呈现锯齿状,每次垃圾回收之后下降到的内存位置越来越高,最后由于垃圾回收无法释放空间导致对象无法分配产生 outOfMemory 的错误。
问题产生原因:程序中保存了大量的内存泄漏对象,导致 GC 之后无法释放,可以使用 MAT 或者 HeapHero等工具 进行分析是哪些对象产生了内存泄漏。

image-20241012095138087

四、持续的 Fu GC

特点:在某个时间点产生多次 FULL GC,CPU使用率 同时飙高,用户请求基本无法处理。一段时间之后恢复正常。问题产生原因:在该时间范围请求量激增,程序开始生成更多对象,同时 垃圾收集 无法跟上对象创建速率,导致持续地在进行 FULL GC。GC分析报告

image-20241012095207463

五、元空间不足导致的 FULL GC

特点:堆内存的大小并不是特别大,但是持续发生 FULL GC。问题产生原因:元空间大小不足,导致持续 FULL GC 回收元空间的数据。GC分析报告

image-20241012095921960

解决 GC 问题的手段

解决GC问题的手段中,前三种是比较推荐的手段,第四种仅在前三种无法解决时选用:

image-20241012100032580

解决问题 -优化基础 JVM参数
参数1:-Xmx 和-Xms

-Xmx 参数设置的是**最大堆内存,**但是由于程序是运行在服务器或者容器上,计算可用内存时,要将元空间、操作系统、其它软件占用的内存排除掉。

  • 案例:服务器内存 4G,操作系统+元空间最大值+其它软件占用 1.5G,-Xmx可以设置为 2g。最合理的设置方式应该是根据最大并发量估算服务器的配置,然后再根据服务器配置计算最大堆内存的值。

image-20241012100423088

参数1:-Xmx 和-Xms
  • -Xms用来设置初始堆大小,建议将-Xms设置的和-Xmx一样大,有以下几点好处:

    1. 运行时性能更好,堆的扩容是需要向操作系统申请内存的,这样会导致程序性能短期下降。
    2. 可用性问题,如果在扩容时其他程序正在使用大量内存,很容易因为操作系统内存不足分配失败。
    3. 启动速度更快,Oracle官方文档的原话:如果初始堆太小,Java应用程序启动会变得很慢,因为 JVM 被迫频繁执行垃圾收集,直到堆增长到更合理的大小。为了获得最佳启动性能,请将初始堆大小设置为与最大堆大小相同。
  • 参数2 :-XX:MaxMetaspaceSize 和 -XX:MetaspaceSize

    • -XX:MaxMetaspaceSize=值 参数指的是最大元空间大小,默认值比较大,如果出现元空间内存泄漏会让操作系统可用内存不可控,建议根据测试情况设置最大值,一般设置为 256m。
    • -XX:MetaspaceSize=值 参数指的是到达这个值之后会触发FULL GC(网上很多文章的初始元空间大小是错误的)后续什么时候再触发 JVM 会自行计算。如果设置为和 MaxMetaspaceSize 一样大,就不会 FULL GC,但是对象也无法回收

image-20241012101010384

参数3:-Xss虚拟机栈大小

如果我们不指定栈的大小,JVM 将创建一个具有默认大小的栈。大小取决于操作系统和计算机的体系结构。
比如 Linu×x86 64位:1MB,如果不需要用到这么大的栈内存,完全可以将此值调小节省内存空间,合理值为256k - 1m之间。
使用:-Xss 256k

参数4:不建议手动设置的参数

由 于JVM底层 设计极为复杂,一个参数的调整也许让某个接口得益,但同样有可能影响其他更多接口。
-Xmn 年轻代的大小,默认值为整个堆的 1/3,可以根据峰值流量计算最大的年轻代大小,尽量让对象只存放在年轻代,不进入老年代。但是实际的场景中,接口的响应时间、创建对象的大小、程序内部还会有一些定时任务等不确定因素都会导致这个值的大小并不能仅凭计算得出,如果设置该值要进行大量的测试。G1垃圾回收器尽量不要设置该值,G1会动态调整年轻代的大小。

image-20241012101400184

-XX:SurvivorRatio 伊甸园区和幸存者区的大小比例,默认值为8。
-XX:MaxTenuringThreshold 最大晋升阈值,年龄大于此值之后,会进入老年代。另外 JVM 有动态年龄判断机制:将年龄从小到大的对象占据的空间加起来,如果大于 survivor 区域的 50%,然后把等于或大于该年龄的对象,放入到老年代。

image-20241012101641612

-XX:+DisableExplicitGC

禁止在代码中使用system·gc(), System·gc() 可能会引起FULL GC,在代码中尽量不要使用。使用 DisableExplicitGC参数 可以禁止使用 system.gc() 方法调用。

  • -XX:+HeapDumpOnOutOfMemoryError:发生 outofMemoryError错误 时,自动生成 hprof内存快照文件。
    -XX:HeapDumpPath= :指定hprof文件的输出路径。
打印 GC 日志

JDK8及之前:-XX:+PrintGCDetails -XX:+PrintGCDateStamps-Xloggc:文件路径
JDK9及之后:-Xlog:gc*:file=文件路径

image-20241012102056910

image-20241012102452337

解决问题优化垃圾回收器的参数

这部分优化效果未必出色,仅当前边的一些手动无效时才考虑

一个优化的案例:

CMS的 并发模式失败(concurrentmodefailure)现象。由于 CMS 的垃圾清理线程和用户线程是 并行进行的,如果在并发清理的过程中老年代的空间不足以容纳放入老年代的对象,会产生并发模式失败。

并发模式失败会导致 Java虚拟机 使用 Serial old单线程 进行 FULL GC 回收老年代,出现长时间的停顿。

image-20241012103938071

@RequestMapping("/fullgc")public class Demo2Controller {private Cache chche = Caffeine.newBuilder().weakKeys().softValues().build();private List<Object> objs = nwe ArrayList<>();private static final int _1MB = 1024 * 1024;// FULLGC 测试// -Xms8g -Xmx8g -Xss256k -XX:MaxMetaspaceSize=512m -XX:+DisableExplicitGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/test.hprof -verbose:gc -XX+PrintGCDetails -XX:PrintGCTimeStamps// ps + po 50并发 260ms 100并发 474 200并发930// cms -XX:UseParNewGC -XX:UseConcMarkSweepGC 50并发 157ms 200并发 833// g1 JDK11 并发200 248@GetMappin("/1")public void test() throws InterruptedException {cache.put(RandomStringUtils.randomAlphabetic(8), new byte[10 * _1MB]);}
}
解决方案:
  1. 减少对象的产生以及对象的晋升。
  2. 增加堆内存大小
  3. 优化垃圾回收器的参数,比如 -XX:CMSInitiatingOccupancyFraction=值,当老年代大小到达该阈值时,会自动进行 CMS垃圾回收,通过控制这个参数提前进行老年代的垃圾回收,减少其大小。
  4. JDK8中 默认这个参数值为 -1,根据其他几个参数计算出阈值:
    ((100 - MinHeapFreeRatio) + (double)(CMSTriggerRatio * MinHeapFreeRatio) / 100.0)
  5. 该参数设置完是不会生效的,必须开启-XX:+UseCMSInitiatingOccupancyOnly参数。

image-20241012104852881

案例实战

image-20241012104951543

image-20241012111403812

image-20241012111725586

image-20241012111752959

image-20241012111922027

image-20241012112340006

image-20241012114431163

性能调优

应用程序在运行过程中经常会出现性能问题,比较常见的性能问题现象是:

  1. 通过 top命令 查看 CPU占用率高,接近100甚至 多核CPU 下超过100 都是有可能的。
  2. 请求单个服务处理时间特别长,多服务使用 skywalking 等监控系统来判断是哪一个环节性能低下。
  3. 程序启动之后运行正常,但是在运行一段时间之后无法处理任何的请求**(内存和GC正常)**

线程转储(Thread Dump)提供了对所有运行中的线程当前状态的快照。线程转储可以通过 jstack、visualvm 等工具获取。其中包含了线程名、优先级、线程ID、线程状态、线程栈信息等等内容,可以用来解决CPU占用率高、死锁等问题。

image-20241012115127955

线程转储者(Thread Dump)中的几个核心内容:

**名称:**线程名称,通过给线程设置合适的名称更容易“见名知意”
优先级(prio): 线程的优先级
JavaID(tid): JVM 中线程的 唯一ID
本地ID(nid): 操作系统 分配给线程的 唯一ID
**状态:**线程的状态,分为:
NEW -新创建的线程,尚未开始执行
RUNNABLE -正在运行或准备执行
BLOCKED - 等待获取监视器锁以进入或重新进入同步块/方法
WAITING -等待其他线程执行特定操作,没有时间限制
TIMED_WAITING -等待其他线程在指定时间内执行特定操作
TERMINATED -已完成执行

  • 栈追踪:显示整个方法的栈帧信息

    线程转储的可视化在线分析平台:
    1.https://jstack.review/
    2.https://fastthread.io/

案例1:CPU 占用率高问题的解决方案

image-20241012121841656

image-20241012121934850

image-20241012122010546

image-20241012122303010

image-20241012122336314

案例2:接口响应时间很长的问题

image-20241012122426168

Arthas 的 trace命令

使用 arthas 的 trace命令,可以展示出整个方法的调用路径以及每一个方法的执行耗时。
命令:trace 类名方法名

  • 添加–skipJDKMethod false 参数可以输出 JDk核心 包中的方法及耗时。
  • 添加‘#cost 〉毫秒值’参数,只会显示耗时超过该毫秒值的调用。
  • 添加 -n 数值参数,最多显示该数值条数的数据。
  • 所有监控都结束之后,输入 stop 结束监控,重置 arthas增强的对象。

image-20241012122629884

总结:

1、通过 arthas的 trace命令,首先找到性能较差的具体方法,如果访问量比较大,建议设置最小的耗时,精确的找到耗时比较高的调用。
2、通过 watch命令,查看此调用的参数和返回值,重点是参数,这样就可以在开发环境或者测试环境模拟类似的现象,通过 debug 找到具体的问题根源。
3、使用 stop命令 将所有增强的对象恢复。

案例3:定位偏底层的性能问题

image-20241012123340608

Arthas 的 profile 命令

使用 arthas 的 profile 命令,生成性能监控的火焰图。
命令1: profiler start 开始监控方法执行性能
命令2: profiler stop – format html 以 HTML 的方式生成火焰图
火焰图中一般找绿色部分Java中栈顶上比较平的部分,很可能就是性能的瓶颈。

image-20241012123955994

image-20241012124326069

性能调优解决的问题

应用程序在运行过程中经常会出现性能问题,比较常见的性能问题现象是:

1、通过 top命令 查看 CPU占用率高,接近 100甚至 多核CPU下 超过 100都是 有可能的。
2、请求单个服务处理时间特别长,多服务使用 skywalking等监控系统 来判断是哪一个环节性能低下。
3、程序启动之后运行正常,但是在运行一段时间之后无法处理任何的请求(内存和GC正常)。

案例4:线程被耗尽问题

image-20241012124557007

image-20241012124957199

image-20241012125114138

解决方案:

3、使用 fastthread 自动检测线程问题。https://fastthread.io/
Fastthread 和 Gceasy类似,是一款在线的Al自动线程问题检测工具,可以提供线程分析报告。通过报告查看是否存在死锁问题。

image-20241012125216702

性能调优的方法

image-20241012141003302

JIT 对程序性能的影响

Java 程序在运行过程中,JIT 即时编译器会实时对代码进行性能优化,所以仅凭少量的测试是无法真实反应运行系统最终给用户提供的性能。如下图,随着执行次数的增加,程序性能会逐渐优化。

image-20241012141142813

OpenJDK 中提供了一款叫 JMH(Java Microbenchmark Harness)的工具,可以准确地对 Java代码 进行基准测试,量化方法的执行性能。

官网地址:https://github.com/openjdk/jmh

JMH 会首先执行预热过程,确保 JIT对代码进行优化之后再进行真正的迭代测试,最后输出测试的结果。

image-20241012141446910

image-20241012141722857

import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*;// 预热次数 时间
@Warmup(iterations = 5, time = 1)
// 启动多少个线程
@Fork(value=1, jvmArgsAppend= {"-Xms1g", "-Xmx1g"})
// 指定显示结果
@BenchamarkMode(Mode.AverageTime)
// 指定显示结果单位
@OutputTimeUnit(TimeUnit.NANOSECONDS)
// 变量共享范围
@State(Scope.Benchmark)
public class MyBenchmark {@Benchmarkpublic void testMethod() {// place your benchmarked code hereint i = 0;i++;return i;}// 在项目中测试时,尽量打包成 jar 包public static void main(String[] args) throws RunnerException {Options options = new OptionsBuilder();.include(MyBenchmark.class.getSimpleName()).forks(1).build();new Runner(options).run();}
}
编写测试方法,几个需要注意的点:
  • 死代码问题

  • 黑洞的用法

  • 通过 maven 的 verify命令,检测代码问题并打包成 jar包。通过 java -jar target/benchmarks.jar 命令执行基准测试。

    测试结果通过 https://imh.morethan.io/ 生成可视化的结果。

案例:日期格式化方法性能测试

image-20241012143940299

总结:日期格式化方法性能测试

image-20241012143835919

案例实战

image-20241012151014091

image-20241012154017957

image-20241012154144670

相关文章:

JVM 实战篇(一万字)

此笔记来至于 黑马程序员 内存调优 内存溢出和内存泄漏 内存泄漏&#xff08;memory leak&#xff09;&#xff1a;在Java中如果不再使用一个对象&#xff0c;但是该对象依然在 GC ROOT 的引用链上&#xff0c;这个对象就不会被垃圾回收器回收&#xff0c;这种情况就称之为内…...

线程同步之双摄

如何实现两个摄像头进行同步&#xff0c;并利用同步的信号做一些事情&#xff0c; 比如stereo camera 做深度&#xff0c;如果是自己整的两个camera&#xff0c;同步就需要自己做&#xff0c; 那么这时候可以利用线程同步手写一个&#xff0c;下面给一个示例代码&#xff1a; …...

使用 PyTorch 构建 LSTM 股票价格预测模型

目录 引言准备工作1. 训练模型&#xff08;train.py&#xff09;2. 模型定义&#xff08;model.py&#xff09;3. 测试模型和可视化&#xff08;test.py&#xff09;使用说明模型调整结论 引言 在金融领域&#xff0c;股票价格预测是一个重要且具有挑战性的任务。随着深度学习…...

【C++篇】C++类与对象深度解析(五):友元机制、内部类与匿名对象的讲解

文章目录 前言 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助&#xff01…...

模型训练进度条的代码

这个内容难在什么地方呢&#xff1f; 我想要跳转到另一个页面的时候 如何保存当前的训练状态&#xff0c;本来还想着加一个页面去管理进度的。然后想到了localstorage&#xff0c;将一些信息存储到浏览器中去。 进度条展示 <el-form-item label"训练进度" v-show…...

直观理解反向传播 | Chapter 3 | Deep Learning | 3Blue1Brown

目录 前言1. 简介2. 回顾3. 直观的演绎示例4. 随机梯度下降相关资料结语 前言 3Blue1Brown 视频笔记&#xff0c;仅供自己参考 这个章节主要来直观地理解反向传播算法到底在做什么 官网&#xff1a;https://www.3blue1brown.com 视频&#xff1a;https://www.bilibili.com/vide…...

052_python基于Python高校岗位招聘和分析平台

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍&#xff1a;CodeMentor毕业设计领航者、全网关注者30W群落&#xff0c;InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者&#xff0c;博客领航之星、开发者头条/腾讯云/AW…...

基于物联网、大数据、人工智能等技术开发的Spring Cloud 智慧工地云平台源码,支持多端应用

系统概述&#xff1a; 智慧工地是指运用现代信息技术&#xff0c;如物联网&#xff08;IoT&#xff09;、大数据、人工智能&#xff08;AI&#xff09;、云计算、移动互联网等&#xff0c;对传统建筑工地进行智能化改造和管理的新型工地。它通过高度集成的系统和设备&#xff…...

常见的跨境电商平台对比【总结表】

常见的跨境电商平台对比【总结表】 平台目标市场费用结构物流服务支付方式推广工具适合卖家亚马逊全球销售佣金、月租费、FBAFBA支持全球配送多种支付方式广告工具、促销活动有一定资金实力的品牌和卖家eBay全球上市费、成交费第三方物流支持PayPal、信用卡广告工具、促销活动…...

perl批量改文件后缀

perl批量改文件后缀 如题&#xff0c;perl批量改文件后缀&#xff0c;将已有的统一格式的文件后缀&#xff0c;修改为新的统一的文件后缀。 #!/bin/perl use 5.010;print "Please input file suffix which U want to rename!\n"; chomp (my $suffix_old <>)…...

【Python中的字符串处理】正则表达式与常用字符串操作技巧!

Python中的字符串处理&#xff1a;正则表达式与常用字符串操作技巧 Python 在字符串处理方面提供了丰富的内置功能和模块&#xff0c;能够帮助开发者处理各种复杂的文本操作。无论是简单的字符串拼接、替换&#xff0c;还是借助正则表达式&#xff08;re 模块&#xff09;实现…...

又是一年一度的1024,那就记录一篇算法博客吧~ 【二进制加法探秘】

前言&#xff1a; 又是一年一度的1024&#xff0c;那就记录一篇算法博客吧~ 内容如下~ 1 题目介绍 给定两个二进制字符串 a 和 b&#xff0c;需要返回它们的和&#xff0c;结果以二进制字符串形式给出。 示例 1&#xff1a; 输入: a “11”, b “1” 输出: “100” 示例 2…...

LeetCode--买卖股票的最佳时机含冷冻期--动态规划

一、题目解析 二、算法原理 我们可以使用dp[i]来表示第i天买卖股票所获得的最大利润。由题可得我们只能持有一支股票&#xff0c;并且在卖出后有冷冻期的限制&#xff0c;因此我们会有三种不同的状态&#xff1a; 我们目前持有一支股票&#xff0c;对应的「累计最大收益」记为…...

装了Ubuntu和Windows双系统,如何设置默认启动Windows

可以将默认启动系统设置为Windows&#xff0c;以下是步骤&#xff1a; 1. 修改GRUB配置文件&#xff1a; • 启动到Ubuntu&#xff0c;打开终端。 • 编辑GRUB配置文件&#xff1a; sudo nano /etc/default/grub • 找到这一行&#xff1a; GRUB_DEFAULT0 将0改为对应Wi…...

WPF+MVVM案例实战-设备状态LED灯变化实现

文章目录 1、项目创建2、UI界面布局1. MainWindow.xaml2、颜色转换器实现2.MainViewModel.cs 代码实现 3、运行效果4.源代码下载 1、项目创建 打开 VS2022 &#xff0c;新建项目 Wpf_Examples&#xff0c;创建各层级文件夹&#xff0c;安装 CommunityToolkit.Mvvm 和 Microsof…...

MySQL--基本介绍

一.数据库前言 1.数据库的相关介绍 关系数据库管理系统&#xff08;Relational Database Management System&#xff1a;RDBMS&#xff09;是指包括相互联系的逻辑组织和存取这些数据的一套程序 (数据库管理系统软件)。关系数据库管理系统就是管理关系数据库&#xff0c;并将数…...

PAT甲级1008 Elevator

题目地址&#xff1a;1008 Elevator - PAT (Advanced Level) Practice (pintia.cn) 介绍 The highest building in our city has only one elevator. A request list is made up with N positive numbers. The numbers denote at which floors the elevator will stop, in spe…...

数据导入导出

1.数据加载 - LOAD 语法 LOAD DATA [LOCAL] INPATH filepath [OVERWRITE] INTO TABLE tablename; 操作: 建表 CREATE TABLE myhive.test_load( dt string comment 时间&#xff08;时分秒&#xff09; , user_id string comment 用户 ID, word string comment 搜索词 , u…...

git的安装以及入门使用

文章目录 git的安装以及入门使用什么是git&#xff1f;git安装git官网 git初始化配置使用方式初始化配置&#xff1a; git的安装以及入门使用 什么是git&#xff1f; Git 是一个免费开源的分布式版本控制系统&#xff0c;使用特殊的仓库数据库记录文件变化。它记录每个文件的…...

【acwing】算法基础课-搜索与图论

目录 1、dfs(深度优先搜索) 1.1 排列数字 1.2 n皇后问题 搜索顺序1 搜索顺序2 2、bfs(广度优先搜索) 2.1 走迷宫 2.2 八数码 3、树与图的存储 4、树与图的遍历 4.1 树的重心 4.2 图中点的层次 5、拓扑排序 6、最短路问题 6.1 朴素Dijkstra算法 6.2 堆优化Dijks…...

502 错误码通常出现在什么场景?

服务器过载场景 高流量访问&#xff1a;当网站遇到突发的高流量情况&#xff0c;如热门产品促销活动、新闻热点事件导致网站访问量激增时&#xff0c;服务器可能会因承受过多请求而无法及时响应。例如&#xff0c;电商平台在 “双十一” 等购物节期间&#xff0c;大量用户同时…...

面试经典算法题69-两数之和

面试经典算法题69-两数之和 公众号&#xff1a;阿Q技术站 LeetCode.1 问题描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。…...

在 Spring 框架中,循环依赖是指两个或多个 Bean 之间相互依赖

在 Spring 框架中&#xff0c;循环依赖是指两个或多个 Bean 之间相互依赖&#xff0c;形成一个闭环。例如&#xff0c;Bean A 依赖于 Bean B&#xff0c;而 Bean B 又依赖于 Bean A。这种情况如果不加以处理&#xff0c;会导致 Bean 无法正确实例化&#xff0c;从而引发应用程序…...

一文带你入门Flink CDC

1 CDC简介 1.1 什么是CDC CDC是Change Data Capture(变更数据获取)的简称。核心思想是,监测并捕获数据库的变动(包括数据或数据表的插入、更新以及删除等),将这些变更按发生的顺序完整记录下来,写入到消息中间件中以供其他服务进行订阅及消费。 1.2 CDC的种类 CDC主要…...

修复jenkins SSH 免密登录发布服务器

SSH 免密登录配置和修复步骤&#xff1a; 1. 配置 SSH 免密登录 在本地主机执行以下命令&#xff0c;将公钥复制到目标服务器&#xff1a; ssh-copy-id bjpark172.27.xx.xx输入密码完成公钥传输。 2. 修复 SSH 免密登录失败的权限问题 如果免密登录失败&#xff0c;用root…...

049_python基于Python的热门微博数据可视化分析

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍&#xff1a;CodeMentor毕业设计领航者、全网关注者30W群落&#xff0c;InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者&#xff0c;博客领航之星、开发者头条/腾讯云/AW…...

中国信通院联合中国电促会开展电力行业企业开源典型实践案例征集

自2021年被首次写入国家“十四五”规划以来&#xff0c;开源技术发展凭借其平等、开放、协作、共享的优秀创作模式&#xff0c;正持续成为推动数字技术创新、优化软件生产模式、赋能传统行业转型升级、助力企业降本增效的重要引擎。电力是国民经济的重要基础性产业&#xff0c;…...

LOAM 20.04 ros1安装

LOAM 安装 LOAM源码 安装参考 上述安装参考在 报错1、 C标准改为17 解决方案 数据集 试车实验...

Pyqt5设计打开电脑摄像头+可选择哪个摄像头(如有多个)

目录 专栏导读库的安装代码介绍完整代码总结 专栏导读 &#x1f338; 欢迎来到Python办公自动化专栏—Python处理办公问题&#xff0c;解放您的双手 &#x1f3f3;️‍&#x1f308; 博客主页&#xff1a;请点击——> 一晌小贪欢的博客主页求关注 &#x1f44d; 该系列文…...

mysqldump 批量导出数据库表

先查询需要导出的数据表&#xff0c;使用语句 SELECT table_name FROM information_schema.tables WHERE table_schema 数据库名 AND table_name LIKE mall%; 再批量导出查询到的表 mysqldump -u root -p test_yogasala mall_ad mall_address mall_admin mall_cart mall_…...

网站建设 南宁/网络推广100种方式

20172303 2017-2018-2 《程序设计与数据结构》第9周学习总结 教材学习内容总结 第十一章 异常 1.异常 异常处理 异常处理的常用方法有三种&#xff1a; 根本不处理当异常发生时处理异常在程序的某个位置集中处理异常处理异常的主要方法是捕获异常异常捕获——try-catch语句 格式…...

做网站是com好还是cn好/哈尔滨百度公司地址

标准库string类型 String类型支持长度可变的字符串&#xff0c;需要包含头文件#include<string> 1、string对象的定义和初始化 string支持好几种初始化方式&#xff1a; 初始化方式 说明 String s1; 默认构造函数&#xff0c;s1是空串 String s2(s1) 将s2初始化为s1…...

天津协会网站建设/网络营销推广方式包括

2019独角兽企业重金招聘Python工程师标准>>> API 包含了两个软件包&#xff0c;十二个接口和九个类。 软件包&#xff1a; javax.servlet 软件包&#xff1a; javax.servlet 所包含的接口&#xff1a;RequestDispatcher&#xff1b;Servlet&#xff1b;ServletConf…...

网站哪里可以做/南宁百度seo优化

ElasticSearch 2 (7) - 基本概念 摘要 ElasticSearch的一些基本核心概念&#xff0c;理解这些概念有助于ElasticSearch的学习 准实时NRT&#xff08;Near Realtime&#xff09;集群节点索引类型文档分片与副本&#xff08;Shards & Replicas&#xff09;版本 elasticsearch…...

网页qq登录入口官网/seo建站公司推荐

工作了&#xff0c;那是个优选的聚集。互相帮助的地方。 学习&#xff0c;一朝一夕&#xff1f;不是。 那么&#xff0c;我问你&#xff0c;你为什么用一两个应答来对我&#xff1f;这个能有什么作用&#xff1f; 自述的形式&#xff0c;各个人&#xff0c;都能整理知识&#x…...

专业做旅游网站/seo搜索引擎优化书籍

人生很多第一次&#xff0c;记录美好的时光&#xff01;-- 认真是这个世界上最伟大的事情 csdn&#xff1a;第一次从千里之外拉回到现在、一直持续、坚持不懈&#xff01;未完待续.........