知方号

知方号

JVM调优实战(二)

JVM调优实战(二)

JVM、OOM、内存泄漏、内存溢出、GC

背景

  接上篇《JVM调优实战(一)》,本节主要介绍生产环境常见的异常类型及处理办法。从实战的角度细说:如何发现问题、分析问题、解决问题。

文章导读

生产问题

  在生产环境中,JVM可能出现,如内存泄漏、内存溢出、线程死锁、GC停顿和性能问题等。

如何处理CPU负载飙高?如何处理内存溢出?如何合理分配服务器内存?如何合理分配线程数?如何选择合适的垃圾回收器?如何优化减少频繁Full GC?

......

  出现上述问题后,势必会引起响应变慢、接口超时、系统卡顿等。通常,我们要分析具体业务场景。并通过系统监控发现问题。

调优步骤发现问题(性能监控)

1、性能指标

响应时间(RT): 提交一次请求和返回该请求的响应之间使用的时间,一般指平均响应时间.常见操作例如:打开一个网站;查询一条SQL;一次远程调用请求;下游系统数据同步等吞吐量: 吞吐量是指在单位时间内系统能处理的请求数量,它体现了系统处理请求的能力,通常反映的是服务器负载的能力。QPS: 即每秒查询率,是评估系统查询处理能力的关键指标。 QPS = 总查询次数 / 总时间(秒).该指标反映系统在单位时间内能够成功处理的查询请求数量.并发数: 是指系统在同一时刻实际处理的请求或事务的数量,反映了系统可以同时承载的正常使用系统功能的用户的数量。一般来说,并发数越高,系统的处理能力越强。

2、性能问题

频繁Full GCCPU负载高死锁OOM内存泄漏

这里给出一个重要的top命令。主要用于排查:内存不断增长,CPU占用率居高不下的进程。 top 查看所有的进程的cpu、内存占比。 top -Hp pid 查看指定pid下各个线程的cpu、内存占比。

$ topPID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                    9757 root      20   0 5173452 140856  14168 S  99.7  1.8  66:19.52 java  分析问题(性能分析)命令行工具,jstack,jmap,jinfo等导出heapdump.hprof文件,使用内存分析工具MAT分析使用JVisualVM或者阿里Arthas来实时查看JVM状态打印GC日志,通过GCviewer或者 gceasy.io来分析日志信息解决问题(性能调优)优化代码,比如循环调用、批量处理等。加机器节点,提高负载能力使用中间件提高吞吐量,比如缓存,异步等通过调整参数配置,例如:合理增加线程数选取合适的垃圾回收器复盘问题(性能考量)

在业务系统中,各种场景都有可能导致系统性能问题。例如:

定时任务处理日增量数据:如果定时任务执行频率过高或处理逻辑复杂,可能导致系统资源(如CPU、内存、I/O)的频繁占用,从而影响其他任务的执行性能。此外,如果任务处理时间过长,还可能影响系统的响应时间。远程第三方平台调用:可能涉及网络延迟和数据传输。如果第三方平台响应缓慢或数据传输量大,可能导致系统等待时间过长,从而影响整体性能。微服务之间接口调用:微服务架构中,服务间的调用可能涉及网络通信和序列化/反序列化操作,这些操作都会带来一定的性能开销。如果服务调用链过长或调用频繁,可能导致系统性能下降。同时,不同服务之间的负载均衡和容错机制也会影响整体性能。远程获取Redis和MQ消息:从Redis和MQ中获取消息时,如果网络延迟较高或消息队列积压严重,可能导致系统等待时间过长,从而影响性能。此外,频繁地从Redis中读取或写入数据也可能导致性能瓶颈。批量处理割接数据:批量处理大量数据可能导致系统资源(如内存、CPU)的占用率急剧上升,从而影响其他任务的执行。大文件上传下载:处理大文件上传下载时,如果文件过大或网络带宽有限,可能导致上传下载速度缓慢,从而影响用户体验和系统性能。同时,处理大文件还可能带来磁盘I/O和内存占用的压力。复杂业务接口查询:复杂的业务接口查询可能涉及多表联查、大量数据计算和聚合等操作,这些操作都可能消耗大量的系统资源,从而影响性能。

  通常在各种应用场景中,我们不仅要对线上产生的问题进行复盘、分享、交流。而且要保持对业务的深刻理解和上线之前的数据量预估,进而对系统性能做出考量。

知道上述的一些基本步骤。接下来,重点聊聊关于JVM性能调优-OOM的案例。

性能优化案例基础配置主机参数:4核8GOracle jdk版本:1.8.0_221

本节演示主机参数:4核8G。真实生产环境可能配置较高,具体在Linux系统下查看内存和CPU核数命令如下

查看内存:

free -h: 显示内存信息cat /proc/meminfo: 显示内存的详细信息,包括总内存、可用内存等。

查看CPU核数:

nproc命令直接输出CPU核心数,是最简单的方法。lscpu命令可以显示CPU的详细信息,包括CPU核心数、架构等。cat /proc/cpuinfo文件也可以获取CPU的相关信息,如物理CPU个数、每个物理CPU的核数等,可以通过grep命令过滤出需要的信息,如cat /proc/cpuinfo | grep "processor" | wc -l可以查看逻辑CPU的个数。

案例一、OOM-堆内存溢出

异常提示:java.lang.OutOfMemoryError: Java heap space

示例代码:

  List list = new ArrayList();  while (true) {      list.add(new Object());  }

参数配置:

官方参考文档:docs.oracle.com/javase/8/do…

这里为了演示效果,为自定义配置

参数配置: 初始 -Xms20m  最大 -Xmx20mjava -jar -Xms20m -Xmx20m -XX:MetaspaceSize=8m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap/heapdump.hprof -XX:+PrintGCDetails -XX:+PrintGCDateStamps   -Xloggc:log/gc-oom-heapspace.log demo-jvm-1.0-SNAPSHOT.jar

演示结果:

监控与分析: MAT 分析dump文件

查看日志文件,也可用工具查看

less -SR /root/log/gc-oom-heapspace.log

原因分析:

1、代码中可能存在大对象分配;

2、可能存在内存泄漏,导致在多次GC之后,还是无法找到一块足够大的内存容纳当前对象。

解决办法:

1、通过问题定位检查是否存在大对象的分配,可能的是大数组或者死循环;

2、使用MAT等工具分析堆内存dump文件,检查是否存在内存泄漏;

3、如果没有找到明显的内存泄漏,使用 -Xmx 加大堆内存

4、容易忽视的是:也有可能是使用框架内部造成的

发生场景:

场景 1:大数据处理

  当应用程序需要处理大量数据,并且这些数据无法全部加载到内存中时,可能会导致堆内存溢出。

案例代码:

public class BigDataProcessor {    public static void main(String[] args) {        List bigDataList = new ArrayList();        // 假设这是从数据库或文件中读取的大量数据        for (int i = 0; i  MAX_CACHE_SIZE) {            cache.remove(cache.keySet().iterator().next());        }    }         private ImageFeature extractFeature(byte[] imageData) {          // 模拟图像处理,提取特征          return new ImageFeature();      }        // ImageFeature 类定义      static class ImageFeature {          // 特征数据      }      public static void main(String[] args) {        ImageProcessor processor = new ImageProcessor();        // 处理图片        for (int i = 0; i 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。