JAVA性能优化思路探究,让程序超顺畅

article/2025/11/9 8:27:02

1、背景介绍

一个系统的上线除了常规的功能性测试外,还需要经过严格的性能测试,满足预期的性能指标(常见的有响应时间,tps等),才允许上生产环境。

广义的性能测试一般还包含负载测试(用于测试系统的容量:即系统在保证一定响应时间的情况下能够允许多少并发用户的访问),压力测试(用于测试系统的稳定性:即在保证一定压力的情况下,查看测试系统的稳定性),并发测试(即测试系统多并发能力:即模拟多用户访问同一应用的测试,用于发现并发问题,比如线程锁,资源竞争,数据库死锁等)等。

通过性能测试,可以帮助我们尽快发现系统的瓶颈。如果发现未能满足预期的业务目标,则需要进行性能调优。性能调优的需求,有时候来自于原型的验证,有时候来自于生产上实际的问题,不管哪一类的性能调优,我们一般按照性能监控,性能分析,性能优化这几个步骤进行。以下章节会对每个步骤进行详细分析。

2、性能监控

性能监控是性能调优的第一步,主要目的在于了解当前系统运行的状态,了解当前服务器资源使用情况,JVM的内存使用,线程使用等情况,以便于第一时间找到瓶颈点。

2.1 查看服务器配置

为了更好评估服务器性能,首先应了解当前宿主服务器的配置情况。以下主要是针对linux服务器给出的常见的查看命令。

2.1.1 CPU配置

对于CPU,比较关心的是CPU的总逻辑核数,可以直接使用mpstat查看。

可以使用cat /proc/cpuinfo查看CPU的型号:

2.1.2 内存配置

使用free命令进行查看,可以看到总的内存,以及使用的情况

 

2.1.3 磁盘配置

使用fdisk -l可以查看到所有的磁盘配置情况,使用df -TH可以看到当前磁盘的目录挂载情况

 

有时候,需要确认当前磁盘是否为SSD盘,判断cat /sys/block/*/queue/rotational的返回值(其中*为你的硬盘设备名称,例如sda等等),如果返回1则表示磁盘可旋转,那么就是HDD了;反之,如果返回0,则表示磁盘不可以旋转,那么就有可能是SSD了。如下图所示,sda是SSD盘。

2.1.4 网络配置

使用ifconfig命令,可以看到网卡的配置情况。有时候,需要查看当前网卡是千M还是万M,可以通过ethtool查看speed可以判断。如下图所示,eth4是千M网卡。

 

2.2 服务器监控

为了能实时了解系统运行时,资源的占用情况,我们就需要对服务器的系统资源进行监控,以下列出常见的命令以及常用的监控事项。

2.2.1 CPU监控

使用vmstat命令,vmstat 2代表每2秒统计一次

 

重点观察

Ø Procs中r值,它代表调度程序运行队列的长度,如果该值长时间大于CPU逻辑核数1倍以上,需要关注,超过3-4倍需要马上采取行动

Ø System中in(中断),cs(上下文切换)如果两值较大,说明系统内核消耗CPU较多

Ø Cpu列中,如果us(用户态)占比长期大于50%时,就需要考虑优化算法。根据经验us+sy占比参考值为80%

可以使用pidstat -w -I -p pid 2,监控应用的锁竞争情况

让步式上下文切换(cswch)时钟周期占用3% ~ 5%,说明Java应用面临锁竞争,抢占式上下文切换率(nvcswch)高,说明预备运行的线程数多于可用的虚拟处理器数。

2.2.2 内存监控

也可以使用上述的vmstat查看内存页面交换,

 

 

重点观察free,si,so这几列,如果free变小,而且si,so在变化,说明存在内存不足,跟磁盘swap,有发生页面交换的情况,需要考虑加大内存。

2.2.3 网络监控

使用第三方软件iptraf,它提供了可视化的页面,通过它可以实时监控网络流量情况。

 

2.2.4 磁盘

使用iostat进行监控

 

cpu属性值说明:

Ø 如果%iowait的值过高,表示硬盘存在I/O瓶颈,%idle值高,表示CPU较空闲,如果%idle值高但系统响应慢时,有可能是CPU等待分配内存,此时应加大内存容量。%idle值如果持续低于10,那么系统的CPU处理能力相对较低,表明系统中最需要解决的资源是CPU。

disk属性值说明:

Ø 如果%util接近100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘可能存在瓶颈。如果svctm比较接近await,说明I/O几乎没有等待时间;如果await远大于svctm,说明I/O队列太长,io响应太慢,则需要进行必要优化。如果avgqu-sz比较大,也表示有当量io在等待。

2.3 JVM监控

使用jdk中自带的jvisualvm工具,在要连接的远程java进程,启动时增加jmx的配置,如下:

 

这样jvisualvm就可以通过ip+1111端口侦听远程JVM的情况了。

2.4 连接池监控

2.4.1 查看数据库连接池数量

使用netstat –an | grep ‘db ip’ | wc –l命令,可以看到与数据库创建的连接池,看这个值跟设置的数据库连接池的最小值,以及最大值的关系。如果始终通过最大值,需要考虑调整连接的最大值。

2.4.2 查看工作线程数

方法1:使用jvisualvm工具远程监控来查看

方法2:使用命令查看

2.5 Oracle监控

2.5.1 查看oracle配置

Ø 使用oracle的用户登录oracle的服务器(su - oracle)

Ø 启动sqlplus命令行模式(sqlplus / as sysdba)

Ø 查看配置(Show parameter sga;)

2.5.2 性能监控

Ø 使用sqlplus命令行模式

Ø 开始时启动快照命令,停止时再执行一遍快速命令

备注:快照命令(exec
DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT();)

Ø 快照执行完后,取报告(@?/rdbms/admin/awrrpt)

Ø 分析报告(重点关注top 5 time events)

3 性能分析

3.1 JVM分析

3.1.1 堆分析

为了不影响线上的性能,可以使用堆转储,命令如下:

jmap -dump:live,format=b,file=heap_dump.hprofpid

然后可以将生成的.hprof文件导入mat,或者jvisualvm进行分析,可以了解哪些对象正在消耗内存。同时对于识别由创建太多某一特定对象所引发的内存问题,软件提供的直方图方法快速且方便。

3.1.2 垃圾回收分析

Jvm启动时,可以设置-Xloggc,-XX:PrintGCDetails等参数,开启gc日志收集。也可以使用jstat进行监控分析,比如jstat–gcutil pid 2用于每隔2秒打印当前Java堆及GC情况。

3.1.3 线程分析

使用jdk自带的JMC和jstack工具,可以查看堵塞的线程。JMC内部集成的JFR可以很方便的检索出引发线程堵塞的事件。而jstack在一定程度上可以检查线程是堵塞在什么资源上。以下给出jstack定位思路:

 

4 性能优化

在深度优化系统前,应该先弄清为何CPU的使用率低。优化代码的目的是提升而不是降低更短时间内的CPU使用率。

4.1 JVM启动参数优化

4.1.1 原生内存的优化

对原生内存的优化,包含使用压缩的OOP(jvm启动参数上增加-XX:+UseCompressedOops)以及调整大内存分页(同时修改linux配置以及jvm启动参数-XX:LargePageSizeInBytes)等,都可以提升性能。

4.1.2 垃圾回收机制的优化

Ø 合理设置堆的大小,以及合理设置好代空间的划分:设置太小容易频繁GC,而设置太大,GC时停顿时间太长。同时为了避免可能使用到虚拟内存,内存页交换导致更慢,至少保留1G的物理内存。

Ø 如何选择各分区大小应该依赖应用程序中对象生命周期的分布情况:如果应用存在大量的短期对象,应该选择较大的年轻代;如果存在相对较多的持久对象,老年代应该适当增大。

Ø 稳定与震荡的堆大小:将-Xms和-Xmx的大小一致,对垃圾回收有利。

4.1.3 大对象分配优化

Ø 大对象尽量分配在TLAB,如果大量发生在TLAB外,需要考虑调整TLAB参数,或者减少分配对象的大小。可以通过-XX:PrintTLAB标志查看结果。

Ø 大对象划入老年代:将大对象直接分配到老年代,保持新生代对象的结构的完整性,以提高GC效率,以通过
-XX:PretenureSizeThreshold设置进入老年代的阀值。

4.2 java编程优化

因为实际的编程中,涉及性能优化的点比较多,以下只是列举一些常见的优化项供参考。

4.2.1 线程池优化

Ø 根据当前服务器CPU的数量合理设置最大线程数,最小线程数,线程池任务队列大小。CPU密集型任务配置尽可能小的线程,如配置Ncpu+1个线程的线程池。IO密集型任务则由于线程并不是一直在执行任务,则配置尽可能多的线程,如2*Ncpu。

Ø 建议使用有界队列,有界队列能增加系统的稳定性和预警能力。

Ø 优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理。

Ø 执行时间不同的任务可以交给不同规模的线程池来处理,或者也可以使用优先级队列,让执行时间短的任务先执行。设置线程的优先级。

4.2.2 其它编程细节

Ø 尽量减少内存的使用,减少对象的大小,设置类型时考虑最小原则,去掉不用的属性,以及没有用到的实例变量。

Ø 通过使用对象池以及线程局部变量的方式来加强对象的重复。对象重用跟GC是有点矛盾,所以主要考虑对象初始化时成本比较高的情况(即初始化时间比较长)。

Ø 对于保存实际不需要在多个线程间共享的同步对象,同时又在不同的实际中进行传递的对象,可以考虑使用线程局部变量,减少同步竞争。

Ø 在一些场景下,优化使用java8并行流的模式

4.3 数据库优化

4.3.1 使用预编译

使用preparedStatement方式,重用预处理语句池可以极大提升性能,同时也要避免出现大量大型对象池化而引起的GC方面的问题。

4.3.2 使用连接池

引入hikari连接池,在启动时就配置好

Ø 创建连接的代价很大,通过JDBC连接池获取连接可省去创建连接时间。同时需要合理设置连接池的大小。

Ø 合理设值:比如设置检索时的批量值,设置最优的预取值,设置ResultSet的批量值,可以提高检索的性能。

Ø 事务的优化:事务的提交以及事务相关的锁机制都会影响系统的性能,需要考虑合理设置事务隔离的级别,以及批量提交的策略等。

5 性能实战经验汇总

5.1 清算并发性能上不去

5.1.1 问题的现象

使用java8的并行流计算时,发现并发的性能上不去,并且性能会随着时间推移,不断的下降

5.1.2 优化点

Ø 引入hikari连接池,将单笔延时降到5ms

Ø 关闭日志

Ø 将sql改成预编译的模式

Ø Oracle服务器的把oracle的内存提高

5.2 Hsiar跟中台的连接上,存在很多FIN_WAIT2连接

5.3 Server_name是否可以随便配置

6 小结

6.1 性能工具箱

6.1.1 压测工具jmeter

Jmter是开源的压测工具,也易于上手。它的使用就不介绍了,这里主要讲一些注意的事项:

Ø 它的实时绘图依赖于服务器端的响应,如果压测机与服务器时间不同步的话,会出现展示图断层现象,为了得到更准确的性能曲线,建议使用命令行的方式。

Ø 有时候发现压测性能上不去,有可能的原因在于客户端。主要考虑的因素:客户端的CPU不足以支持所需数量的客户端线程,或者客户端需要花大量时间处理响应后才能发送请求。

6.1.2 JVM相关

除了上文提到的jdk自带的工具外,还有IBM提供的MemoryAnalyzer,以及商用软件jprofile都很强大。

6.1.3 数据库相关

对于数据库的性能监控,可以使用Spotlight,它有基于mysql以及oracle的不同版本支持。

6.1.4 网络相关

常用Linux自带的Tcpdump命令导出抓包,然后使用wireshark进行分析,很强大。

本文主要是针对java性能调优的一般思路的总结,以及分享一些在性能优化上常用的最佳实践。希望对大家有帮助。


http://chatgpt.dhexx.cn/article/q6GcBkYl.shtml

相关文章

Java接口性能优化实例

Java接口性能优化实例 文章目录 Java接口性能优化实例概述用到的工具和环境工具环境 找瓶颈启示和收获 概述 最近公司的下单接口有些慢,老板担心无法支撑双11,想让我优化一把,但是前提是不允许大改,因为下单接口太复杂了&#xf…

JAVA程序性能优化

制约程序性能的根源 常用的性能评估指标 并发:同一时间多少请求访问:如同一时间10个用户请求,并发就是10TPS:transaction per second:相当于写操作QPS:query per second:相当于读请求&#xf…

Java性能优化的35个细节(珍藏版)

代码优化,一个很重要的课题。可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗&#xff1…

Java 中 10 大简单的性能优化

Java 7 ForkJoinPool和 Java 8 的并行Stream有助于并行化东西,这在您将 Java 程序部署到多核处理器机器上时非常有用。与跨网络上的不同机器进行扩展相比,这种并行性的优势在于您几乎可以完全消除延迟效应,因为所有内核都可以访问相同的内存。…

Java性能优化的七个方向

博客主页:https://tomcat.blog.csdn.net 博主昵称:农民工老王 主要领域:Java、Linux、K8S 期待大家的关注💖点赞👍收藏⭐留言💬 目录 概述复用优化计算优化并行执行变同步为异步惰性加载 结果集优化资源冲…

JAVA性能优化实例

目录 概述 Sql性能优化 多线程 利用内存缓存 功能优化 参考博客 概述 性能优化的几个点,大致可以分为: sql优化使用多线程利用内存,缓存等,将固定不常更改的数据放入在,存取更快的内存当中功能实现逻辑优化 Sql性…

10种简单的Java性能优化学习

10种简单的Java性能优化学习 你是否正打算优化hashCode()方法?是否想要绕开正则表达式?Lukas Eder介绍了很多简单方便的性能优化小贴士以及扩展程序性能的技巧。 最近“全网域(Web Scale)”一词被炒得火热,人们也正在…

Java性能优化实践:分享Java性能优化的实践经验

Java性能优化是一个非常重要的话题,在现代软件开发中扮演着至关重要的角色。在本篇博客中,我将分享一些Java性能优化的实践经验,包括使用JavaProfiler分析程序性能、使用JMH进行基准测试、优化JVM参数等,帮助开发者更好地理解Java…

11 个简单的 Java 性能调优技巧

大多数开发人员理所当然地以为性能优化很复杂,需要大量的经验和知识。好吧,不能说这是完全错误的。优化应用程序以获得最佳性能不是一件容易的事情。但是,这并不意味着如果你不具备这些知识,就不能做任何事情。这里有11个易于遵循…

Java性能优化

文章目录 一、JVM内存模型1.1、程序计数器(Program Counter Register)1.2、JVM虚拟机栈(JVM Stacks)1.3、本地方法栈(Native Method Stacks)1.4、堆(Heap)1.5、方法区(Me…

Java性能优化的50个细节(珍藏版)

在JAVA程序中,性能问题的大部分原因并不在于JAVA语言,而是程序本身。养成良好的编码习惯非常重要,能够显著地提升程序性能。 1. 尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要…

GNU-ARM程序开发(一)----GNU开发环境和工具

什么是GNU GNU计划,又称革奴计划。是由Richard Stallman在1983年9月27日公开发起的。目标是创建一套完全免费、自由的操作系统,基本原则是源代码共享及思想共享。 所有在GNU计划下开发的软件均为GNU软件。 为保证GNU软件可以自由地“使用、复制、修改和发…

【ARM编程】ARM介绍

01.ARM目录 ARM目录 01.ARM目录02.前言03.计算机体系结构分类04.ARM公司05.ARM应用领域06.ARM基本架构07.ARM各体系架构版本7.1 ARM版本Ⅰ:V1版架构7.2 ARM版本 Ⅱ:V2版架构7.3 ARM版本 Ⅲ:V3版架构7.4 ARM版本 Ⅳ: V4版架构7.5 A…

ARM开发环境

目录 前言一、Ubuntu及linux系统基础知识1.shell命令的运用2.Tool的安装:3.deb是软件包,dpkg是手动安装工具,apt是自动安装工具,4.Linux文件系统5.gcc编译器 二、开发环境搭建1.vim编辑器2.与windows文件互传3.VSCode使用4.NFS网络…

ARM开发环境下载地址大全

MDK5.3.8a(Keil5)最新下载地址 超链接如下,点击直达: Keil MDK (Keil Licensing) (MDK000) (arm.com) 实际网址如下所示: https://developer.arm.com/downloads/view/MDK000 Arm Compiler for Embedded下载地址 超链接如下,点击直…

什么是ARM?

原文 一、ARM是什么? ARM既可以认为是一个公司的名字 ,也可以认为是对一类处理器的统称 ,还可以认为是一种技术的名字 。 ARM公司是专门从事基于RISC技术芯片设计开发 的公司,作为知识产权供应商,本身不直接从事芯片…

X86ARM架构

这里写目录标题 cpu架构arm架构ARM架构图 x86架构arm架构和x86架构的区别CISC Vs RISCWindows如何查看系统是ARM64还是X64架构 32位与64位的区别巨头公司国产cpu公司 cpu架构 CPU 的全称是"中央处理单元",它是计算机的核心,计算都由它来完成。…

ARM开发——常见仿真器

搞嵌入式开发和ARM开发搞了半辈子了,调试程序是不可避免的。接触了那么多的调试规范、调试工具、调试手段,彼此之间的关系却也不是特别清楚,今天就来捋一捋: JTAG协议 JTAG(Joint Test Action Group,联合…

ARM开发---基础认识

本文适合初次接触ARM的的初学者,主要以基础知识点和科普为主. 文章目录 前言一、ARM是什么?二、ARM的特点三、ARM的使用场景1.计算机组成2.架构3.指令集4.指令解析5.工作模式 四、寄存器总结 前言 提起ARM,没有接触过的朋友可能第一反应是英…

【嵌入式】Linux开发工具arm-linux-gcc安装及使用

arm-linux-gcc 知识架构及层次 — 程序编译及调试嵌入式交叉编译器安装配置主机目标板开发模式ARM微处理器/Linux系统下编译器编译器下载及安装 arm-linux-gcc工具使用-E-S-c -o-include file-I dir-I-iprefix prefix 和 -iwithprefix dir-l库名 -L目录gcc 优化 课后作业 Linux…