JVM 优化

零、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

       demo地址:  https://gitee.com/-/ide/project/sunxj1222/sunxj-javaBase/edit/master/-/sunxj-jvm/src/main/java/com/base/MaxDirectMemoryTest.java

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Tomcat中的JVM优化是指对Java虚拟机的调优,以提高Tomcat服务器的性能和稳定性。根据引用[1],Tomcat的JVM优化主要包括以下几个方面: 1. 内存设置:通过调整JVM的堆内存大小,可以提高Tomcat的性能。可以通过修改Tomcat根目录下的bin目录中的catalina.sh(Linux)或catalina.bat(Windows)文件来设置JVM的内存参数,如-Xms和-Xmx参数分别用于设置JVM的初始堆大小和最大堆大小。 2. 垃圾回收设置:垃圾回收是JVM的重要功能,可以通过调整垃圾回收算法和参数来优化Tomcat的性能。可以使用-Xloggc参数来指定垃圾回收日志文件的路径,以便进行分析和调优。 3. 线程池设置:Tomcat使用线程池来处理客户端请求,可以通过调整线程池的大小和配置来优化Tomcat的性能。可以修改Tomcat根目录下的conf目录中的server.xml文件,通过修改Connector元素的属性来设置线程池的参数,如maxThreads和minSpareThreads。 4. 连接设置:可以通过调整Tomcat的连接参数来优化Tomcat的性能。例如,可以设置maxKeepAliveRequests属性来限制每个连接的最大请求数,以避免产生大量的TIME_WAIT连接。 需要注意的是,JVM优化需要根据具体的应用场景和硬件环境进行调整,不同的应用可能需要不同的优化策略。建议在进行JVM优化之前,先进行性能测试和监测,以便确定需要进行的优化方向和参数调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值