JVM调优

本文深入探讨了JVM调优的三个方面:规划与预调优、优化运行环境和解决问题。内容包括根据业务场景选择合适的垃圾回收器、计算内存需求、设置JVM参数、处理高并发场景、解决CPU和内存问题。通过实例分析,讲解了如何使用各种JVM工具(如jstat、jstack、jmap等)进行问题定位和优化,并给出了具体的调优策略和参数设置建议。
摘要由CSDN通过智能技术生成

咱们前面了解了类加载器、内存管理、垃圾回收算法、垃圾回收器等一堆的理论知识,只有理论没有实践就相当于纸上谈兵,那么咱们接下来看看什么是jvm调优,如何调

什么是JVM调优

jvm调优一般可以分3类

1、根据需求进行JVM规划和预调优
2、优化运行JVM运行环境(慢,卡顿)
3、解决JVM运行过程中出现的各种问题(OOM)

如何调

JVM规划和预调优

1、熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)
	1、响应时间,停顿时间[CMS G1 ZGC]
	2、吞吐量 = 用户时间/(用户时间+GC时间)
2、选择回收器组合
3、计算内存需求
4、选定CPU(根据预算越高越好)
5、设定年代大小、升级年龄
6、设定日志参数
	1、-Xloggc:/opt/xxx-xxx-gc-%t.log -XX:+UsrGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
	2、或者每天产生一个日志文件
7、观察日志
计算服务内存
问:每秒1000订单的服务器需要多大的内存?
这个问题咱们首先需要计算每个订单的大小,假如单个订单的大小需要512K那么就需要
512 * 1000 = 500M 内存
一般情况设置要大于500M,这样可以减少GC频率
秒杀
超高并发量如何处理?
架构思想:
	1、分而治之
	2、分层
如:12306的一种可能的模型:下单->减库存和订单同时异步进行->等待付款

优化运行JVM运行环境

有一个50万PV的资料类网站
从磁盘提取文档到内存,原服务器32位,1.5G的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了
为什么原网站慢?
	很多用户浏览数据,很多数据load到内存,内存不足,频繁GC,STW时间长,响应慢
为什么会更卡顿?
	内存越大,FGC时间越长
如何优化?
	PS+PO---换成 PerNew+CMS或者G1
	从架构上讲再分服务器,减小内存

JVM运行过程中出现的各种问题

一般问题分为两种,CPU或者内存问题

系统CPU经常100%

CPU占用100%一定有线程在占用系统资源

1、找出那个进程CPU高
	top
2、该进程中哪个线程CPU高
	top -Hp 进程id
		打印出进程下每个线程CPU和memory使用情况
3、导出该线程的堆栈
	jstack 进程id 
4、查找哪个方法(栈帧)消耗时间
	jstack 日志 
5、找出工作线程占比高还是垃圾回收线程占比高
6、根据分析出的问题去解决

常用命令:
	top -Hp pid: 查看进程中线程使用情况
	jinfo pid: 查看VM运行时参数及其他信息
	jstack pid: 查看堆栈快照信息
	jmap -histo pid | head -20: 堆栈对象信息及导出dump文件
	jstat -cg pid 500: 监控虚拟机运行状态信息
	jhat dumpfilename : http://ip:7000 查看分析结果
系统内存飙高
1、java -Xms200M -Xmx200M -XX:+PrintGC xxxx.java
2、一般运维团队首先收到报警信息(CPU Memory)
3、top命令观察到问题:内存不断增长CPU占用率居高不下
4、top -Hp 观察进程中的线程,哪个线程CPU和内存占比比较高
5、jps 定位具体java进程
		jstack 定位线程状况,重点关注:WAIATING BLOCKED
6、jinfo pid 查看JVM运行时数据
7、jstat -gc 动态观察gc情况/阅读GC日志发现频繁GC /arthas观察 /jconsole /jprofile(最好用)
	  jstat -gc pid 500:每500个毫秒打印GC的情况
	  比如:waiting on <0x0000000088ca3310> (a java.lang.Object)等待锁的释放
      假如有一个进程中有100个线程,很多线程都在waiting on <xxx>,一定要找到哪个线程持有这把锁
      怎么找:搜索jstack dump的信息,找<0x0000000088ca3310>中 RUNNABLE 的那个线程
    	1、已经上线的系统不用图形界面用什么?(command line arthas)
    	2、图形界面到底用到什么地方?
    			测试!测试的时候进行监控
8、查看堆前20行信息,查找有多少对象产生
		jmap -histo 4655 | head -20 
9、手动导出堆文件 
		jmap -dump:format=b,file=xxx pid 
		线上系统,内存特别大,jmap执行期间会对进程产生很大影响,甚至卡顿
      	1、设定了参数 -XX:+HeapDumpOnOutOfMemoryError,OOM的时候会自动产生堆转储文件
      	2、很多服务器备份(高可用),停掉这台服务器对其他服务器不影响
      	3、在线排查
     分析堆文件
     		jhat filename
     				jhat -J-mx512M filename 指定dump文件加载大小(分页导入)
     				http://ip:7000
     				拉到最后:找到对应连接
     				可以使用OQL查找特定问题对象
10、java -Xms20M -Xmx20M -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError xxx.java
11、使用MAT / jhat 进行dump文件分析
12、找到代码的问题

调优过程常用的工具

jstat(java自带工具)、jvisualvm(java自带工具)、jprofiler、arthas ...
arthas阿里开源,官网下载:arthas-boot.jar
启动arthas
	java -jar arthas-boot.jar
arthas命令
	1、jvm 类似jinfo命令 列出jvm版本、虚拟机名称(HotSpot)、垃圾回收器集合、运行用户等等信息
	2、thread 定位线程信息
	3、dashboard 可以查看线程,内存,os运行时状态
	4、heapdump (可以指定文件)导出堆信息。--尽量不要使用,最好线上分析
	5、jad 反编译
			jad com.package.Classname
			1、动态代理生成类的问题定位
			2、第三方的类(观察代码)
			3、版本问题(确定自己最新提交的版本是不是被使用)
	6、redefine 热替换

JVM调优常用的参数

OOM问题

设置参数
1、server.max-http-head-size=10000000 #默认4096k
	每一个http请求头大小为10000000,长时间就OOM了
2、StackOverFlow栈溢出
		调整-Xss参数
3、内存一直消耗不超过10%,但是一直频繁GC。
		引起原因:有人显示的调用 System.gc();
4、new 大量线程,会产生native thread OOM (low)应用线程池
		JVM内存占物理内存比例 50%~80% 

G1 FGC

如果G1产生FGC,应该怎么做
	1、扩内存
	2、提高CPU性能(回收的块,业务逻辑产生对象的速度固定,垃圾回收越快,内存空间越大)
	3、降低MixedGC触发的阀值,让MixedGC提早发生(默认是45%)

GC 参数

通用参数
-XX:+DisableExplictGC=设置SYstem.gc()不管用,默认打开,建议打开

-Xmn=年轻代
-Xms=最小堆
-Xmx=最大堆
-Xss=栈空间

-XX:+UseTLSB=使用TLAB,默认打开
-XX:+PrintTLAB=打印TLAB
-XX:TLABSize=设置TLAB大小
-XX:+DisableExplictGC=设置System.gc()不管用 FullGC

-XX:+PrintGC=打印GC日志
-XX:+PrintGCDetails=打印GC详细日志
-XX:+PrintHeapAtGC=打印堆栈的情况
-XX:+PrintGCTimeStamps=打印GC的时候系统时间
-XX:+PrintGCApplicationConcurrentTime=打印应用程序时间
-XX:+PrintGCApplicationStoppedTime=打印暂停时长(STW时)
-XX:+PrintReferenceGC=记录回收了多少种不用引用类型的引用
-verbose:class=类加载详细过程

--必须就使用
-XX:+PrintVMOptions=打印VM运行时的详细参数
-XX:+PrintFlagsInitial=打印参数初始
-XX:+PrintFlagsFinal=打印参数最终的 java -XX:PrintFlagsFinal -version | grep G1
-Xloggc:opt/log/gc.log=记录GC日志
-XX:+MaxTenuringThreshold=GC升代年龄

--不建议设置
	-XX:PreBlockSpin=自选次数 -XX:CompileThreshold=热点代码检查
Parallel常用参数
-XX:+UseSerialGC=
-XX:SurvivorRatio=
-XX:PreTenureSizeThreshold=大对象的大小,大对象会直接进到Old区
-XX:MaxTenruingThreshold=GC升代年龄
--并行收集器的线程数,同样适用于CMS,一般设为和CPU核数相同
	-XX:+ParallelGCThreads=一般不用调 
		java -XX:+PrintFlagsFinal -version | grep ParallelGCThreads
--自动选择各区大小比例
	-XX:+UseAdaptiveSizePolicy
CMS常用参数
-XX:+UseConcMarkSweepGC=
-XX:ParallelCMSThreads=CMS线程数量默认是一半,(old区,不能设置太大)
-XX:CMSInitiatingOccupancyFraction
	=使用多少比例的老年代后开始CMS收集,默认是68%(近似值),如果频繁发生SerialOld卡顿,应该调小,频繁		CMS回收
--解决浮动垃圾 进行整理(耗时比较长)
  -XX:+UseCMSComPactAtFullCollection=在FullGC时进行压缩
  -XX:+UseCMSFullGCsBeforeCompaction=多少次FGC后进行压缩
-XX:+CMSClassUnloadingEnable=回收方法区不用的class
-XX:CMSInitiatingPermOccupancyFraction=达到什么比例时进行Perm回收
一个建议时间
  GCTimeRatio=设置GC时间占用程序运行时间的百分比
  -XX:MaxGCPauseMillis=停顿时间,是一个建议时间,GC会尝试用各种手段达到这个时间比如减少年轻代
G1常用参数
-XX:+UseG1GC=使用G1
-XX:MaxGCPauseMillis=建议值,G1会尝试调整Young区的块数来达到这个值
-XX:GCPauseIntervalMillis=
	
-XX:G1HeapRegionSize=分区大小,建议逐渐增大1 2 4 8 16 32
		随着size增加,垃圾的存活时间更长,GC间隔更长,每次GC的时间也会更长
		ZGC做了改进(动态区块大小)
G1NewSizePercent=新生代最小比例,默认5%
G1MaxNewSizePercent=新生代最大比例,默认60%
GCTimeRatio=GC时间 建议比例,G1会根据这个值调整整堆空间
ConcGCThreads=线程数量
InitiatingHeapOccupancyPercent=启动G1的堆空间占用比例

PS:如果有帮助到您,请关注下博主点个赞吧~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值