暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

jvm性能优化小入门

老范的自留地 2017-11-27
189

缘起

我司项目现在的java项目都是基于springboot开发,通过Jenkins与ansible直接把项目编译的jar在阿里云主机上部署运行,几台云主机的配置大都是通用型2核8G,java项目难免遇到诸如内存溢出这类错误,为了让程序在服务器上有最佳运行效果,需要对每个项目进行jvm调优,JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps、jstack、jmap、jhat、jstat等小巧的工具,本文希望能起抛砖引玉之用,让大家能开始对JVM性能调优的常用工具有所了解

  1. jps:查看所有java项目进程 
    一般我都用: jps -m -l PID 这样会列出 
    21996 usr/local/platform/patient/bin/patient.jar –spring.profiles.active=test 
    21996 是进程id 
    /usr/local/platform/patient/bin/patient.jar 是详细的进程名称 
    –spring.profiles.active=test 是传入main类或者jar包的参数

  2. jstack :查看某个java进程内的堆栈信息,根据堆栈信息,我们可以定位到具体代码,在jvm性能调优中使用的特别多! 
    我一般这么用: jstack -m -l PID 
    其中 -m 参数不仅会列出java对战信息,还会列出系统级别native方法的c/c++堆栈信息 
    -l 会打印出额外的锁信息

    栗子:我们找我patient这个java进程最消耗CPU的线程

    • 首先用jps获取patient这个java进程的ID 
      21996 /usr/local/platform/patient/bin/patient.jar –spring.profiles.active=test

    • 得到进程ID为21996,第二步找出该进程内最耗费CPU的线程,可以用top -Hp 21996 得到如下:

Threads: 32 total,   0 running, 32 sleeping,   0 stopped,   0 zombie

%Cpu(s):  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

KiB Mem : 1867248 total,   94444 free, 1592828 used,   179976 buff/cache

KiB Swap: 2097148 total, 2064196 free,   32952 used.   73720 avail Mem

PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND

21996 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

21999 root     20 0 2564180 241912 7580 S  0.0 13.0   0:05.11 java

22000 root     20 0 2564180 241912 7580 S  0.0 13.0   0:16.09 java

22001 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

22002 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.01 java

22003 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

22004 root     20 0 2564180 241912 7580 S  0.0 13.0   0:15.24 java

22005 root     20 0 2564180 241912 7580 S  0.0 13.0   0:06.93 java

22006 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

22007 root     20 0 2564180 241912 7580 S  0.0 13.0   5:06.79 java

22081 root     20 0 2564180 241912 7580 S  0.0 13.0   0:01.29 java

22082 root     20 0 2564180 241912 7580 S  0.0 13.0   0:01.67 java

22101 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.43 java

22121 root     20 0 2564180 241912 7580 S  0.0 13.0   0:11.48 java

22123 root     20 0 2564180 241912 7580 S  0.0 13.0   0:01.42 java

22149 root     20 0 2564180 241912 7580 S  0.0 13.0   0:13.73 java

22150 root     20 0 2564180 241912 7580 S  0.0 13.0   0:17.81 java

22232 root     20 0 2564180 241912 7580 S  0.0 13.0   0:08.78 java

22233 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.10 java

22234 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.03 java

22235 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

22236 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

22237 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

22238 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

22239 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

22240 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

22241 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

22242 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java

22243 root     20 0 2564180 241912 7580 S  0.0 13.0   0:07.24 java

22244 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.02 java

22245 root     20 0 2564180 241912 7580 S  0.0 13.0   0:14.57 java

36964 root     20 0 2564180 241912 7580 S  0.0 13.0   0:00.00 java


其中TIME+这一列是指耗时时间,这一列里面22007 最耗时,我们在命令行里用printf “%x\n” 22007 得到16进制55f7

  • 这时候用jstack 21996 55f7 来输出堆栈信息如下: 
    “VM Periodic Task Thread” os_prio=0 tid=0x00007ff3980f0800 nid=0x55f7 waiting on condition 
    经过发现这个堆栈信息显示的线程状态是waiting on condition,意思是正在等待网络读写,这可能是一个网络瓶颈征兆。 
    如果这里列出来的是一个java类名,则就可以找到项目里的类,结合堆栈信息,进行性能改进

    1. jmap: 一般结合jhat用来查看堆栈内存使用情况, 
      jmap -heap 21996 显示堆内存如下:

Attaching to process ID 21996, please wait

Debugger attached successfully.

Server compiler detected.

JVM version is 25.141-b16

using thread-local object allocation.

Mark Sweep Compact GC

Heap Configuration:

MinHeapFreeRatio         = 40

MaxHeapFreeRatio         = 70

MaxHeapSize              = 478150656 (456.0MB)

NewSize                  = 10485760 (10.0MB)

MaxNewSize               = 159383552 (152.0MB)

OldSize                  = 20971520 (20.0MB)

NewRatio                 = 2

SurvivorRatio            = 8

MetaspaceSize            = 21807104 (20.796875MB)

CompressedClassSpaceSize = 1073741824 (1024.0MB)

MaxMetaspaceSize         = 17592186044415 MB

G1HeapRegionSize         = 0 (0.0MB)


这里我们可以看到我们堆内存各个区的内存大小。注意:这个是jdk1.8的,其中MetaspaceSize代替了PermGen

优化

上面介绍了用jvm的工具查看java进程,并查找相应堆栈信息,根据堆栈信息优化程序,也列出了堆栈内存的大小信息,要避免内存溢出,在程序在承受较大访问量的时候,程序仍然可以健康运行,就要根据自己机器情况,多做几次抗压试验,找出性能最好的参数设置 
首先jdk8 运行时通常包含 计数器,栈,堆,本地方法栈,方法区,堆。每个部分的优化参数名称如下:

Xss:每个线程的栈内存大小

Xmx:JAVA HEAP的最大值、默认为物理内存的1/4

Xms:JAVA HEAP的初始值,server端最好Xms与Xmx一样

Xmn:JAVA HEAP young区的大小

XX:PermSize:设定内存的永久保存区域

XX:MaxPermSize:设定最大内存的永久保存区域


我基于jdk1.8 做了一个优化参数,我司单台服务器的配置(2核8G),单台服务器我部署2台服务,配置如下(主要是堆栈)

exec java \

-Dfile.encoding=UTF-8 \

-Xss1024K//栈内存1m

-Xms1024m//堆内存最小1g

-Xmx2048m//堆内存最大2g

-Xmn256m //yong

-XX:MaxMetaspaceSize=512m //方法区512m

###常规项目优化

-XX:+DisableExplicitGC //忽略手动调用GC, System.gc()的调用就会变成一个空调用,完全不触发GC

-XX:+UseConcMarkSweepGC //并发标记清除(CMS)收集器

-XX:+CMSParallelRemarkEnabled //降低标记停顿

-XX:LargePageSizeInBytes=128m //内存页的大小

-XX:+UseFastAccessorMethods //原始类型的快速优化

-XX:+UseCMSInitiatingOccupancyOnly //使用手动定义初始化定义开始CMS收集

-XX:CMSInitiatingOccupancyFraction=70 //使用cms作为垃圾回收使用70%后开始CMS收集

-Duser.timezone=GMT+8 //避免CentOS坑爹的时区设置

-XX:+UseG1GC \

-XX:MaxGCPauseMillis=100 \

-XX:InitiatingHeapOccupancyPercent=35 \

######gc信息打印

-verbose:gc \

-XX:+PrintGCDetails \

-XX:+PrintGCDateStamps \

-XX:+PrintGCTimeStamps \

-XX:+PrintGCApplicationStoppedTime \

-Xloggc:${BASE_DIR}/logs/jvm_gc.log \

-XX:ErrorFile=${BASE_DIR}/logs/jvm_err.log \

-XX:+HeapDumpOnOutOfMemoryError \

-XX:HeapDumpPath=${BASE_DIR}/logs/jvm_dump_pid%p.hprof \

-jar /usr/local/platform/patient/bin/patient.jar --spring.profiles.active=prod


各位项目还是要根据自己公司服务器配置情况来进行相应优化测试


文章转载自老范的自留地,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论