Java排查问题工具、命令总结

来源:互联网 发布:oracle数据库自学视频 编辑:程序博客网 时间:2024/05/19 19:34

这一次给大家分享一下Java命令行排查问题的一些工具,主要是排查OOM,线程堵塞等多线程高并发场景下带来的一些问题。其中涉及到一些JVM的基础知识,没有接触过相关知识的同学可以先看一下JVM的内存模型图,大概做一个了解

Java排查问题工具、命令总结

JVM内存模型图

jps命令:

jps是jdk提供的查看Java进程的工具,全程是JavaVirtual Machine Process Status Tool

直接命令行输入jps就可以查看当前的Java进程了

Java排查问题工具、命令总结

ps命令:

查看当前进程的工具之一,可以查看当前进程的运行状态,是否结束,是否是僵尸进程,占用了多少资源等等

一般和grep管道进程连用,用来查看当前Java进程的信息

Java排查问题工具、命令总结

这一串东西看上去乱七八糟的,好像并不能看懂

没关系,我们把管道命令去掉,标题栏显示出来之后就能看懂了

Java排查问题工具、命令总结

关注红框里的这一行,通过询问度娘,我们可以知道:

• USER:该进程属于那个使用者账号的?

• PID :该进程的进程ID号。

• %CPU:该进程使用掉的 CPU 资源百分比;

• %MEM:该进程所占用的物理内存百分比;

• VSZ :该进程使用掉的虚拟内存量 (Kbytes)

• RSS :该进程占用的固定的内存量 (Kbytes)

• TTY :该进程是在那个终端机上面运作,若与终端机无关,则显示 ?,另外, tty1-tty6 是本机上面的登入者程序,若为 pts/0 等等的,则表示为由网络连接进主机的程序。

• STAT:该程序目前的状态,主要的状态有:

R :该程序目前正在运作,或者是可被运作;

S :该程序目前正在睡眠当中 (可说是 idle 状态啦!),但可被某些讯号(signal) 唤醒。

T :该程序目前正在侦测或者是停止了;

Z :该程序应该已经终止,但是其父程序却无法正常的终止他,造成 zombie (疆尸) 程序的状态

• START:该进程被触发启动的时间;

• TIME :该进程实际使用 CPU 运作的时间。

• COMMAND:该程序的实际指令为什么?

对应上Java进程里的那张图,可以知道,Java进程的pid是32727 ,占了0.3%的CPU,占了34.6%的物理内存,用了8372988kb的虚拟内存,占用的固定内存量是2797004kb,与终端机无关,当前进程在睡眠中,是一个多线程的进程

后面跟着的那一串则是JVM参数,配合之前学过的JVM相关知识,不难看懂

Xms4g:JVM初始分配的堆内存这里是4G

Xmx4g:JVM最大允许分配的堆内存这里是4G

会发现xms == xmx,是因为避免动态分配内存影响性能

PermSize=96M: JVM初始分配的非堆内存 96M

MaxPermSize=256m:JVM最大允许分配的非堆内存 256M

perm区主要存放的是Class的信息,主要在JIT期间和classload期间被写入,如果程序会load很多class,perm区分配过小的话,在classload的时候会引发OOM

Xmn2g: JVM分配的young区内存 2G

SurvivorRatio=10 E区比s0,s1的比例,这里是10,表示E区占10/12,s0,s1各占1/12,调整这个数值可以改变E区的大小,从而改变youngGC的频率

UseConcMarkSweepGC:

Young区:可以使用普通的或者parallel 垃圾回收算法,由参数 -XX:+UseParNewGC来控制

Old 区:只能使用Concurrent Mark Sweep

UseCMSCompactAtFullCollection表示在FGC之后进行压缩,因为CMS默认不压缩空间的

CMSMaxAbortablePrecleanTime:当abortable-preclean阶段执行达到这个时间时才会结束,修改这个参数可以缩小CMS-concurrent-abortable-preclean阶段的时间

CMSClassUnloadingEnabled:相对于并行收集器,CMS收集器默认不会对永久代进行垃圾回收。如果希望对永久代进行垃圾回收,可用设置标志

CMSInitiatingOccupancyFraction=80:该值代表老年代堆空间的使用率。比如,value=75意味着第一次CMS垃圾收集会在老年代被占用75%时被触发

DisableExplicitGC:该标志将告诉JVM完全忽略系统的GC调用(不管使用的收集器是什么类型)

UseCMSInitiatingOccupancyOnly:标志来命令JVM不基于运行时收集的数据来启动CMS垃圾收集周期。而是,当该标志被开启时,JVM通过CMSInitiatingOccupancyFraction的值进行每一次CMS收集,而不仅仅是第一次。

HeapDumpOnOutOfMemoryError:JVM会在遇到OutOfMemoryError时拍摄一个“堆转储快照”,并将其保存在一个文件中

HeapDumpPath=/home/mapp/logs/java.hprof :dump快照的位置

MaxDirectMemorySize:该参数指定了DirectByteBuffer能分配的空间的限额,如果没有显示指定这个参数启动jvm,默认值是xmx对应的值。

ExplicitGCInvokesConcurrent:

跟上面的第一个例子的-XX:+DisableExplicitGC一样,这两个参数也是用来改变System.gc()的默认行为用的;不同的 是这两个参数只能配合CMS使用(-XX:+UseConcMarkSweepGC),而且System.gc()还是会触发GC的,只不过不是触发一个 完全stop-the-world的full GC,而是一次并发GC周期(liuinsect注:一次并发周期其实就是在CMS下的一次gc,CMS只能用在full gc 中,所以,也是一次full gc 只不过效率比较高罢了)。

CMS GC周期中也会做reference processing。所以如果用这两个参数的其中一个,而不是用-XX:+DisableExplicitGC的话,就避开了由full GC带来的长GC pause,同时NIO direct memory的OOM也不会那么容易发生。

基本上常用的JVM参数就是上述这些,目前的开发还没有涉及到JVM参数的更改,暂时先把原理了解清楚,把概念梳理一下记录下来,日后用到的时候比较方便查看。

jstat命令:

jstat -gcutil pid time

用自带的jstat命令来查看当前Java进程的gc情况

Java排查问题工具、命令总结

其中E,S0,S1为JVM内存中的新生代,初始对象被放在E中,当E中满了之后触发Young GC

并将E区中存活的对象移到S区中的一个,并对该区进行清理。幸存的会拷贝进入另一个s区中,其中经过多次GC存活的对象会移入old区中

Java排查问题工具、命令总结

当old区中满了,还有新的对象晋升之后,则会触发Major GC。

Major GC即是full GC,对old区的清理采用的是标记、压缩算法会引起stop-the-world

jstat里FGC的次数即是stop-the-world的次数

需要注意的是CMS 不等于Full GC,我们可以看到CMS分为多个阶段,只有stop the world的阶段被计算到了Full GC的次数和时间,而和业务线程并发的GC的次数和时间则不被认为是Full GC

jstack命令:

除了jstat之外,jstack也是一个非常常用的工具,用来对Java进程的运行情况进行探查。尤其是服务运行缓慢、莫名其妙没有响应等情况非常有效

一般来说都是配合jps使用,先查出Java对应的PID

Java排查问题工具、命令总结

Java线程运行周期里有以下这几种状态:

NEW:状态是指线程刚创建, 尚未启动

RUNNABLE状态是线程正在正常运行中, 当然可能会有某种耗时计算/IO等待的操作/CPU时间片切换等, 这个状态下发生的等待一般是其他系统资源, 而不是锁, Sleep等

BLOCKED这个状态下, 是在多个线程有同步操作的场景, 比如正在等待另一个线程的synchronized 块的执行释放, 或者可重入的 synchronized块里别人调用wait() 方法, 也就是这里是线程在等待进入临界区

WAITING这个状态下是指线程拥有了某个锁之后, 调用了他的wait方法, 等待其他线程/锁拥有者调用 notify / notifyAll 一遍该线程可以继续下一步操作, 这里要区分 BLOCKED 和 WATING 的区别, 一个是在临界点外面等待进入, 一个是在理解点里面wait等待别人notify, 线程调用了join方法 join了另外的线程的时候, 也会进入WAITING状态, 等待被他join的线程执行结束

TIMED_WAITING这个状态就是有限的(时间限制)的WAITING, 一般出现在调用wait(long), join(long)等情况下, 另外一个线程sleep后, 也会进入TIMED_WAITING状态

TERMINATED这个状态下表示 该线程的run方法已经执行完毕了, 基本上就等于死亡了(当时如果线程被持久持有, 可能不会被回收)

观察一下用户进程处于的状态,如果大多数处于BLOCKED状态,则很有可能是程序陷入了死锁,运用得好非常利于问题地排查

top -Hp

在需要性能调优或者需要知道当前进程内部资源的消耗情况时,就需要用到top命令了

Java排查问题工具、命令总结

top命令

top命令会按照耗费CPU的情况进行排序

Java排查问题工具、命令总结

转化成16进制

用printf命令将其转化成16进制

再用jstack进行查找,就能查到CPU的具体消耗情况。

当然由于举例的代码里没有什么消耗资源的情况,所以看不出什么,如果真是因为某个方法或者类消耗了大量CPU资源,通过这个方法是可以定位到具体的代码的。

Java排查问题工具、命令总结

学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群346942462,我们一起学Java!

原创粉丝点击