JVM调优思路整理

垃圾回收维度

  • (1)GC日志:停顿时间和吞吐量

停顿时间:垃圾收集器进行垃圾回收终端执行响应的时间
		停顿时间小适用于 和用户交互比较多的场景
吞吐量:用户代码执行时间/(用户代码执行时间+垃圾收集时间)
			用户代码运行占用CPU的时间较长,适合运算、跑后台任务的场景
根据业务和硬件对垃圾回收器分类
	停顿时间比较小的收集器:CMS、G1适用于web应用  (并发类的收集器)
	吞吐量有限:ParaOld Paralle Scanvent			(并行类的收集器)
	串行收集器:Serial 和Serial Old   	用户内存较小,嵌入式的
  • (2)内存使用的维度

      垃圾收集器的选择:
      	如果应用程序对停顿时间没有特别的要求的话,就首先使用JVM默认的垃圾收集器。如果,默认的不能满足你的要求,
      	就要自己进行设置。
      	1.如果应用程序的内存空间比较小(小于100M)
      		选择用 -XX:UserSerialGC
      	2.如果应用程序是单线程的并且没有停顿时间的要求
      		选用 -XX:UserSerialGC
      	3.如果应用程序不关注停顿时间,更加关注吞吐量
      		可以让JVM自己选择,或者用并行的收集器 -XX:UserParallelGC
      	4.如果对停顿时间有要求
      		选择: -XX:UserConcMarkSweepGC  或则和 -XX: UserG1GC
    
      查看java的命令:
      jps 查看java进程命令
      jinfo -flags [option] 进程ID
    

发生OMM怎么办

  • (1)、JVM参数 (分为三类)

    a.类--标准参数(不会随着JDK版本的变化而发生变化)
		java -version / -help
	b.类-- -X参数(非标准参数,随着JDK的版本而变动)
		java -Xint -version(将JVM变成解释模型)  java -Xcomp -version(将JVM变成编译模型)  java -Xmixed -version(将JVM变成混合模型)
	c.类-- -XX参数
		1.boolean 类型
			-XX:[+/-]name  表示 启用/停止name 指令
		2.非boolean 类型
			-XX:name=value 设置name=value例如  -XX:MaxHeapSize=100M;设置最大堆内存100M
	d.其他参数[-XX参数的变行]
		-Xms100M  等同于  -XX:InitialHeapSize=100M
		-Xmx100M  等同于  -XX:MaxHeapSize=100M
		-Xss100K  等同于  -XX:ThreadStackSize=100K
  • ((2).查看JVM参数命令

      java -XX:+PrintFlagsFinal -version
    
  • (3).设置参数的方式

      a.idea 、Eclipse
      b.java -XX:+UserG1Gc xxx.jar
      c.java中间件可以通过修改配置文件  如tomcat修改 bin目录下的catalina.sh文件
      d.jinfo实时修改
      
      参数列表:
      	-XX:ClCompilerCount =3		最大并行编译数			编译速度会提高,但是同样影响系统稳定性。会增加JVM崩溃的可能
      	-XX:InitialHeapSize=100		初始化堆大小			简写-Xms100M
      	-XX:MaxHeapSize=100			最大堆内存				简写-Xmx100M
      	-XX:NewSize=20M				设置年轻代大小			
      	-XX:MaxNewSize=20M			年轻代最大大小
      	-XX:OldSize=100M			设置老年代大小
      	-XX:MetaspaceSize=50M		设置方法去大小
      	-XX:MaxMetaspaceSize=50M	方法去最大大小
      	-XX:UseParallelGC			使用ParallelGC		新生代,吞吐量优先
      	-XX:UseParalleOldGc			ParalleOldGc		老年代,吞吐量优先
      	-XX:UseConcMarkSweepGC		使用CMS				老年代,停顿时间优先
      	-XX:UseG1GC					使用G1				新生代、老年代,停顿时间优先
      	-XX:NewRatio				新生代比例				比如-XX:NewRatio=4,表示新生代:老年代=1:4,也就是整个新生代占堆内存的1/5
      	-XX:+HeapDumpOnOutOfMemoryError   发生oom时输出    
      	-XX:heapDumpPath=heap.hprof		dupm文件名
    
  • (4).java的命令

jps  	查看java当前的进程有哪些
		jinfo	查看或者修改JVM当前参数 
				查看信息--例如:
					查询是否使用G1垃圾收集器 jinfo -flag UserG1GC PID
					查询最大的堆内存 jinfo -flag MaxHeapSize PID
					查询可以赋值的值: jinfo -flags PID
				修改信息--例如:
					jinfo -flag name=value PID
		jstat:查看java当前的正在进行类、gc等信息
			jstat -class PID 1000 10 查看类的当前装载的信息  每隔1000ms输出一次 一共输出10次
			jstat -gc PID	1000 10  查看当前进程的gc的信息, 每隔1000ms输出一次 一共输出10次
		
jstack:查看线程的堆栈信息
			jstack pID打印出当前进程的线程的内容。 
			作用:如果线程发生问题了, 便于排查问题。 例如:线程发生死锁。
		jmap:生成堆内存的快照
			jmap -heap PID
			作用:可以查看堆的信息。当方式OOM的时候,能够找到产生了哪些大对象占用了内存空间。 
		
这个信息可以导出来dump文件。 语法:jmap -dump:format=b,file=heap.hprof PID
			
设置当OOM时候到处dump文件-XX:+HeapDumpOnOutOfMemoryError -XX:heapDumpPaht=heap.hprof

工具

  • 内存分析工具

      	1.jconsole
      	2.jvisualvm
      		visualGC插件
      	3.arths
      		
      	memoryAnalyzer(MAT)工具 拿到dump文件,
      	可以对内存文件进行分析
    
  • GC日志分析工具

	-XX:PrintGCDetails  //打印GC日志
	-Xloggc:gc.log		//保存再gc.log文件
	
	gcviewer.jar工具可以分析gc.log日志

JVM调优

调优是在两个维度
一、堆内存的使用
	运用工具查看堆/栈的状态
二、垃圾回收的效率(关注吞吐量还是关注停顿时间)

G1垃圾收集器调优:

将gc日志导出。 然后用gcview进行分析 吞吐量 最大停顿时间   最小停顿时间  平均停顿时间   gc次数

进行调优:
	将堆内存扩大  -xms:500M -xmx:500M 
	控制停顿时间  -XX:MaxGCPauseMillis=15 设置最大停顿时间为15ms。
		停顿时间建议不要控制的太严格。
调节启动并发GC时堆内存使用占比(默认时45%)
	-XX:InitiatingHeapOccupancyPercent=50  再堆的使用率到达50%的时候 进行并发回收。
		何为并发回收?
			也就是堆Regison区域的回收

G1调优需要注意的点:(官网)
	1、不要调整Yong区的大小或者设置-XX:NewRatio的值。 这样会破环它的停止时间
	2、停顿时间不要设置的太严格。因为严格的停顿时间会增加GC的次数
	3、堆并发回收的参数可以进行调整
		a.-XX:InitiatingHeapOccupancyPercent  设置出发并发回收的阈值
		b.	-XX:G1MixedGCLiveThresholdPercetn  mixed出发的时候存活的比例 
			-XX:G1HeapWastePercent  允许堆内存的浪费比例
		c.-XX:G1MixedGCCountTarget 和 -XX:G1OldCSetRegionThresholdPercent
		
G1和CMS的区别?
	G1适用于新生代和老年代,G1会重新整理内存空间为Region区。G1可以是指停顿时间,G1堆CPU有要求的:必须是多核 内存大的
	
	G1采用的方式时Garbage First的方式。
		解释:优先收集垃圾比较多的区域。因为Region区会被标记为Yong Old 或者大对象
	
高并发的场景下如果进行调优?

问题整理:

一、垃圾收集发生的时间是什么时候?

	Full GC = Major GC + Minor GC +Metaspace Gc;
	(1)Eden区或者S区的空间不够用的时候 ---->MinorGC
	(2)老年代的空间不够用的时候  ----->Major GC  出发MajorGC往往会伴随着Full GC	
	(3)方法区不够用了也会出发GC
	(4)System.gc()方法调用的时候,但是这只是向虚拟机发出一个
	指令。但是什么时候发生回收,还不能确定。
	只能让虚拟机自己决定。

二、如果Full GC频繁怎么办?或者如何减少Full GC的次数?

	适当的将Yong区增大。 设置YOng和Old的占比。尽可能让对象
	再Yong区进行回收	

三、如果GC的次数频繁,会怎么办?

	首先拿到gc的日志。然后通过工具进行分析日志。
	如果是堆内存空间不够用,则要适当的增加堆内存。
	也许是选择的垃圾回收器不太合适。 
	如果用的G1垃圾回收器,查看设置的停顿时间是否太严格了。或者堆内存使用比例是不是太小了。

四、如果cpu飙升怎么办?

	使用top命令查看时哪个进程占用cpu比较大
	(1)因为并发量太大了。导致一些占用cpu的运算一直处于运算中
			解决方案:搭建集群。增加MQ延缓代码的处理
	(2)查看线程是否存在死循环

五、如果发生了OOM怎么办?

	通过dump文件查看oom。分析dump文件  工具MAT

内存泄漏和内存溢出有区别嘛?
	内存泄漏是指:哪些对象没法进行回收,持续的占用内存空间。
	内存溢出:OMM是指内存没法装下对象

方法去中的回收主要是什么内容?
	没有用的类的信息、常量、静态变量
	
	再问:类的信息什么时候被回收?
		(1)堆中不再有该对象
		(2)加载该类的classCloader已经被回收。因为classLoader是可以作为GC Root的
		(3)java.lang.Class对象也不再有任何地方引用了

六、不可达的对象一定会被回收嘛?

	finalize()方法可以自救。

七、Yong GC会有STW嘛?

	考虑垃圾收集器中是否有暂停用户业务代码的操作。
	会有STW

七、排查java导致cpu升高的代码?

1、ps –ef | grep tomcat 命令拿到当前执行的java进程
比如拿到进程号为1000
2、top -H -p 1000  查看该进程中线程占用cpu的情况。
比如查看到线程id为2000的占用cpu比例比较高
3、printf "%x\n" 2000  将线程id转换成16进制 
结果为7D0
4、jstack 1000|grep 7D0 -A 30 打印出该线程的执行信息
"pool-1617252-thread-1" prio=10 tid=0x00007f76a00e5800 nid=0x73c runnable [0x00007f7658e61000]
   java.lang.Thread.State: RUNNABLE
        at java.util.Random.next(Random.java:139)
        at java.util.Random.nextDouble(Random.java:394)
        at java.lang.Math.random(Math.java:695)
        at com.xxx.xxx.utils.Rand.randomNoSame(Rand.java:100)
        at com.xxx.xxx.videos.GetVideoListService.getUserPullDownVirtualPageResult(GetVideoListService.java:275)
        at com.xxx.xxx.videos.GetVideoListService.getVideoList(GetVideoListService.java:94)
        at sun.reflect.GeneratedMethodAccessor1123.invoke(Unknown Source)

你可能感兴趣的:(JVM)