我司项目如今的java项目都是基于springboot开发,经过Jenkins与ansible直接把项目编译的jar在阿里云主机上部署运行,几台云主机的配置大都是通用型2核8G,java项目不免遇到诸如内存溢出这类错误,为了让程序在服务器上有最佳运行效果,须要对每一个项目进行jvm调优,JDK自己提供了不少方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps、jstack、jmap、jhat、jstat等小巧的工具,本文但愿能起抛砖引玉之用,让你们能开始对JVM性能调优的经常使用工具备所了解java
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包的参数c++
jstack :查看某个java进程内的堆栈信息,根据堆栈信息,咱们能够定位到具体代码,在jvm性能调优中使用的特别多!
我通常这么用: jstack -m -l PID
其中 -m 参数不只会列出java对战信息,还会列出系统级别native方法的c/c++堆栈信息
-l 会打印出额外的锁信息spring
栗子:咱们找我patient这个java进程最消耗CPU的线程springboot
首先用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 stKiB Mem : 1867248 total, 94444 free, 1592828 used, 179976 buff/cacheKiB Swap: 2097148 total, 2064196 free, 32952 used. 73720 avail MemPID 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类名,则就能够找到项目里的类,结合堆栈信息,进行性能改进app
jmap: 通常结合jhat用来查看堆栈内存使用状况,
jmap -heap 21996 显示堆内存以下:jvm
Attaching to process ID 21996, please waitDebugger attached successfully.Server compiler detected.JVM version is 25.141-b16using thread-local object allocation.Mark Sweep Compact GCHeap Configuration:MinHeapFreeRatio = 40MaxHeapFreeRatio = 70MaxHeapSize = 478150656 (456.0MB)NewSize = 10485760 (10.0MB)MaxNewSize = 159383552 (152.0MB)OldSize = 20971520 (20.0MB)NewRatio = 2SurvivorRatio = 8MetaspaceSize = 21807104 (20.796875MB)CompressedClassSpaceSize = 1073741824 (1024.0MB)MaxMetaspaceSize = 17592186044415 MBG1HeapRegionSize = 0 (0.0MB)
这里咱们能够看到咱们堆内存各个区的内存大小。注意:这个是jdk1.8的,其中MetaspaceSize代替了PermGenide
上面介绍了用jvm的工具查看java进程,并查找相应堆栈信息,根据堆栈信息优化程序,也列出了堆栈内存的大小信息,要避免内存溢出,在程序在承受较大访问量的时候,程序仍然能够健康运行,就要根据本身机器状况,多作几回抗压试验,找出性能最好的参数设置
首先jdk8 运行时一般包含 计数器,栈,堆,本地方法栈,方法区,堆。每一个部分的优化参数名称以下:
Xss:每一个线程的栈内存大小Xmx:JAVA HEAP的最大值、默认为物理内存的1/4Xms: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
各位项目仍是要根据本身公司服务器配置状况来进行相应优化测试