赞
踩
零、Jvm优化方向
1、主要关注两个目标: 响应速度(responsiveness,stop the world time) 和/或 吞吐量(throughput,tps).
一、问题排查工具
1、查看gc日志输出日志:./jstat -gccause vmid 1000 500| awk '{print $0"\t" strftime("%H:%M:%S",systime())}'
nohup jstat -gccause vmid 1000 600| awk '{print $0"\t" strftime("%H:%M:%S",systime())}' |tee /opt/app/gccause1.txt &
2、查看gc日志不输出日志:date|tee /opt/applog/master-gc.log;./jstat -gccause vmid 1000 500|tee -a /opt/applog/master-gc.log
3、查看heap对象的个数:./jmap -histo -F vmid|tee /opt/applog/histo
(注: num(行号)、instances(实例数)、bytes(大小)、Class description(类的全限定名))
如:
4、生成.hprof/.dump文件:./jmap -dump:format=b,file=/opt/applog/master_dump.hprof vmid
dump文件分析:java_pid10192.hprof eclipse打开—>左键List Objects—>withOutGoing references—>Java local对象
发生OOM(OutOfMemoryError)时,可通过配置-XX:+HeapDumpOnOutOfMemoryError来将堆中的数据保存在文件中,-XX:HeapDumpPath=d://a.dump指定文件的保存路径
分析文件:MAT内存分析工具使用实例java_liao0801_123的博客-CSDN博客_mat内存分析工具使用
5、heap存储快照:./jmap -heap vmid
6、线程快照:./jstack vmid
(nid : 对应的Linux操作系统下的tid线程号,也就是前面转化的16进制数字;
tid: 这个应该是jvm的jmm内存规范中的唯一地址定位)
查看os中的进程的cpu使用情况:top
产看进程中线程的cpu使用情况:top -H -p (vmid)
问题排查过程:找出top -H -p (vmid)中cpu使用高的线程pid,转化为16进制的nid(nid=printf "%x\n" pid)和jstack得出的快照(nid)作对比,即可定位问题线程。
参考:关于JVM CPU资源占用过高的问题排查_NeilNiu的博客-CSDN博客_jvm查看cpu占用过高
【JVM调优系列】----CPU过高的分析与解决方案_令仔很忙的博客-CSDN博客_jvisiualvm 解决cpu过高
查看jvm进程:ps -ef|grep java
查看占用cpu最长的子线程:top -Hp 进程号--->线程号
将线程号转为16进制:printf "%x\n" 线程号--->16进制线程号
查看jvm线程:jstack 进程号|grep 16进制线程号
7、查看jvm为单个线程分配的大小(Xss):
操作系统对线程的限制:ulimit -a
JVM对线程的限制:java -XX:+PrintFlagsFinal -version | grep ThreadStackSize
JVM某个进程对线程的限制:Xss(为每个线程分配栈的大小)
查看某个进程的线程数:ps -m vmid|wc -l
stackOverFlow:单线程纵向请求栈的深度不够,报的错
OOM:多线程横向扩展导致达到了ulimit -u对线程的限制
注:ulimit -u 数字,只能往小调可以,往大调报错(-bash: ulimit: max user processes: cannot modify limit: Operation not permitted),但只是针对本窗口的变更,重新打开个串口即可。若想永久变更,要vim /etc/security/limits.conf--->新 增: @用户名 hard(限制死)/soft(预警) nproc 值(10240)
8、打印gc日志相关:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:d:\gc.log===> 打印gc详情,并附时间
-XX:+PrintGCDetails -Xloggc:d:\gc.log ===>作用是gc前后对比,invocations=2 (full 1) 2次gc,1次fgc
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\gc.dump ===>作用是oom生成heap快照
-Xms4M -Xmx4M -Xmn1M -Xloggc:d:\gc.log -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=8k
-XX:UseGCLogFileRotation===>打开或关闭GC日志滚动记录功能,要求必须设置 -Xloggc参数
-XX:NumberOfGCLogFiles===>设置滚动日志文件的个数,必须大于等于1(gc.log.0、gc.log.9.current 注:重启时从0开始)
-XX:GCLogFileSize===>设置滚动日志文件的大小,必须大于8k
注:CMS的System.gc()--->触发fgc的同时,会将young区的内容晋升到old区。好处是之后的ygc不会有太多内容在s0和s1之间来回copy,导致ygc时间过长。 cms-gcDetail日志
(1)cms日志说明:
a、minor-gc(young):[GC (Allocation Failure)
b、major-gc(old):[GC (CMS Initial Mark)--->[CMS-concurrent-mark--->[GC (Allocation Failure)--->[GC (CMS Final Remark)--->[CMS-concurrent-sweep
c、full-gc(heap):[Full GC (System.gc())
注:Full GC会对整个堆进行垃圾回收,并且会将年轻代存活的对象全部转移到老年代。
(2)parallel scavenge日志说明
a、ygc:[GC (System.gc()) [PSYoungGen: 472044K->38401K(1529344K)] 472044K->38425K(5024768K), 1.1539655 secs]
b、 fgc:[Full GC (System.gc()) [PSYoungGen: 38401K->0K(1529344K)] [ParOldGen: 24K->36971K(3495424K)] 38425K->36971K(5024768K), [Metaspace: 20518K->20517K(1067008K)]
注:默认1h一次fgc。-Dsun.rmi.dgc.server(client).gcInterval = 3600000ms
9、查看JVM参数的默认值可以通过: java -XX:+PrintFlagsFinal -version |grep JVMParamName获取
10、jmap -clstats vmid:打印jvm堆的类加载器的统计数据,对每个类加载器会输出它的名字、是否存活、地址、父类加载器、以及它已经加载的类的数量及大小
11、直接内存OOM: -XX:MaxDirectMemorySize=XXmb
Runtime.getRunTime().maxMemory() ---------------->-Xmx,-Xms
VM.maxDiectMemory()-------------------------------->-XX:MaxDirectMemorySize
a、如果设置了-XX:MaxDirectMemorySize 那么VM.maxDiectMemory()就是 -XX:MaxDirectMemorySize的大小。如果没有指定-XX:MaxDirectMemorySize,那么VM.maxDiectMemory()就是 -Xmx,-Xms的大小。
b、当DirectMemory到达 -XX:MaxDirectMemorySize=XXmb 时,会引起fgc(System.gc() )
注:-XX:+DisableExplicitGC 有这个则会发生oom,因为不会System.gc()
c、ygc时,会回收new区里的DirectByteBuffer(以及其对应的DirectMemory)在不被引用的情况下,会被gc调。而无法回收old区里的DirectByteBuffer(以及其对应的DirectMemory)。所以尽量让DirectByteBuffer在ygc时消灭掉(如:用完时,将DirectByteBuffer = null jvm可调参数有:-XX:PretenureSizeThreshold、-XX:MaxTenuringThreshold)
d、在DirectMemory中分配20M内存:ByteBuffer.allocateDirect(20*1024*1024);
注:netty用的是ByteBur,均为冰山对象
e、获取DirectMemory已使用大小:SharedSecrets.getJavaNioAccess().getDirectBufferPool().getTotalCapacity();
f、Dio.netty.leakDetectionLevel=advanced 这个指令配置再环境中,打印netty哪些内存得不到释放,通过这些日志回得到问题得所在。
g、如果DirectByteBuffer一直被引用,那么DirectByteBuffer(以及其对应的DirectMemory)都不会被gc调,直至oom:direct buffrer memory
h、JVM NativeMemoryTracking 分析堆外内存泄露 jvm参数:-XX:NativeMemoryTracking=ON 。查看jcmd vmidVM.native_memory scale=MB JVM NativeMemoryTracking 分析堆外内存泄露_varyall的博客-CSDN博客_nativememorytracking
12、不设置各区间大小时,收集器的内存分配情况
parallelOld:个区间自适应大小
cms:各区间大小不设置的话,old=2.4young
G1:个区间自适应大小
13、进入old区的场景
a、分配内存时,对象大小大于 -XX:PretenureSizeThreshold
b、分配内存时,对象大小大于eden的一半
c、ygc时,s1<eden+so存活的对象
d、fullgc时,young所有对象会晋升到old
e、gc-age大于 -XX:MaxTenuringThreshold
https://www.cnblogs.com/andywangit/p/16004924.html
14、gc时,对象回收
15、大对象
二、 jit编译优化
注:jit编译以方法为单位
1、java文件------>(编译)class文件----->(翻译)machine code----->os------>CPU
2、编译器
a、-server:C2
b、-client:C1
c、-XX:+TieredCompilation(分层编译:前期-client,后期-server,jdk1.8默认方式)
3、编译缓存
-XX:ReservedCodeCacheSize--->machine code缓存,64位默认240mb
-XX:InitialCodeCache--->machine code初始缓存大小,64位默认2.5MB
注:如果codeCache满了报:Vm varning:CodeCache is full
4、编译阈值
a、jvm中,是否加到codecache基于两个计数,一个是方法被调用的次数,另一个是方法中循环被弹回的执行的次数。达到一定的次数就被加到codecache中
b、-XX:CompileThreshold--->server默认为10000,client默认为1500
5、编译线程
a、一个方法拥有编译资格时,它会排队并等待编译,这个队列是由多个线程组成的
b、这些队列并不会fifo,哪个一个方法调用技术高,哪个就有优先权(这也是为什么编译id在PrintComplication的输出结果中失序)
c、-XX:C1ComplierCount--->这个事线程总数,对于TieredCompilation,前期(clent)有三分之一个,后期(erver)有三分之二个
6、编译详情
a、jvm启动参数中加:-XX:PrintCompilation
b、nohup jstat -printcompilation vmid 10000 600| awk '{print $0"\t" strftime("%H:%M:%S",systime())}' |tee /opt/app/1jvm_100thread_Circularly.txt &
Compiled:内部编译任务的ID
Size:被编译的代码大小
Type:
Method:被(JIT-compile)编译的方法
c、jstat -compiler vmid
Compiled: 编译的方法个数
Failed
Invalid
Time
FailedType
FailedMethod:编译失败的方法名
7、逃逸分析 对象在方法中没有逃逸的话,可直接在栈上分配内存,弹栈时可将对象消灭,不用gc。
三、jdk8内存特点
1、heap: 对象实例、string常量池、包装类型常量池(如:Integer、Byte -128~127)、class对象、static 变量保存在 Class 实例的尾部, static变量位置
2、metaspace:比较大的元数据,比如方法、字节码 、运行时常量池(字面量、符号引用), metaspace范围[20.8m, maxMetaspaceSize],当到达外部设置的-XX:MetaspaceSize时,会触发fgc metaspace介绍
3、compressedClassSpaceSize:只包含类的元数据,比如InstanceKlass, ArrayKlass (注:默认超过1g时,会发生fgc)
注:-XX:+UseCompressedClassPointers 开启后 -XX:CompressedClassSpaceSize=1G 才有效,jdk1.8是默认打开的
- -XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails==============》Caused by: java.lang.OutOfMemoryError: Metaspace
- -XX:CompressedClassSpaceSize=1M ============》Caused by: java.lang.OutOfMemoryError: Compressed class space
-
- //无限产生字节码
- while(true) {
- Thread.sleep(1);
-
- System.out.println(i++);
-
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(Sheep.class);
- enhancer.setUseCache(false);
- enhancer.setCallback(new MethodInterceptor() {
- @Override
- public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
- return null;
- }
- });
- enhancer.create();
- }

4、jdk8(8g内存)建议启动参数:
-server -Xms4G -Xmx4G -Xmn1G -XX:+UseConcMarkSweepGC
-XX:+CMSScavengeBeforeRemark【fgc前执行ygc:目的是减少young对old区的引用,减少remark的开销】 -Dsun.rmi.dgc.server.gcInterval=900000000 -Dsun.rmi.dgc.client.gcInterval=900000000
-XX:+UseCMSInitiatingOccupancyOnly【用设定的回收阈值(CMSInitiatingOccupancyFraction),如果不指定,JVM仅在第一次使用设定值,后续则自动调整】 -XX:CMSInitiatingOccupancyFraction=75 -XX:MetaspaceSize=500M
-XX:MaxMetaspaceSize=500M
64位平台上默认打开:-XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection
-XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M
jdk1.6后默认打开:-XX:+HandlePromotionFailure
四、本地Eclipse配置调优
-vmargs
-Dcom.sun.management.jmxremote
-Dosgi.requiredJavaVersion=1.5
-Xverify:none//取消字节码验证
-Xmx512m
-Xms512m
-Xmn128m
-XX:PermSize=96m
-XX:MaxPermSize=96m
-XX:+DisableExplicitGC//取消system.gc()
-Xnoclassgc//不对perm中的类进行回收
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=85
五、JVM相关参数
参考: Java 虚拟机 (JVM) 统计信息 (Sun Java System Application Server Enterprise Edition 8.1 2005Q2 管理指南)
堆内存
heap_init:堆内存初始字节数
heap_max:堆内存最大字节数
heap_commited:堆内存提交字节数
heap_used:堆内存使用字节数
非堆内存
non_heap_init:非堆内存初始字节数
non_heap_max:非堆内存最大字节数
non_heap_commited:非堆内存提交字节数
non_heap_used:非堆内存使用字节数
直接缓冲区
direct_capacity:直接缓冲区总大小(字节)
direct_used:直接缓冲区已使用大小(字节)
内存映射缓冲区
mapped_capacity:内存映射缓冲区总大小(字节)
mapped_used:内存映射缓冲区已使用大小(字节)
GC(垃圾收集)累计详情
GcPsMarkSweepCount:垃圾收集 PS MarkSweep 数量
GcPsScavengeCount:垃圾收集 PS Scavenge 数量
GcPsMarkSweepTime:垃圾收集 PS MarkSweep 时间
GcPsScavengeTime:垃圾收集 PS Scavenge 时间
JVM 线程数
ThreadCount:线程总数量
ThreadDeadLockCount:死锁线程数量
ThreadNewCount:新建线程数量
ThreadBlockedCount:阻塞线程数量
ThreadRunnableCount:可运行线程数量
ThreadTerminatedCount:终结线程数量
ThreadTimedWaitCount:限时等待线程数量
ThreadWaitCount:等待中线程数量
六、内存分析工具mat
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。