应用上线之后总会出现各种各样的问题,这些问题包括但不限于一下几类问题:
- 线程问题
- cpu消耗较多
- 内存问题
- 进程莫名crash或者被系统kill
- gc时间过长
在排查这类问题时,jdk提供了一系列工具帮助开发人员更好地定位问题。
jstack
jstack主要用来排查线程相关的问题,比如应用内线程数飚高,线程死锁,以及应用cpu过高,在遇到此类问题时可以通过jstack打印出线程栈信息。首先通过ps命令或者jps找出应用的进程id,然后通过jstack将栈信息打印到文件中;
jstack的用法如下:
通过jstack可以知道应用内的线程数正在做什么,常用的用法是通过jstack -l <pid> > stack_<pid>.log,将线程栈信息打印到文件中,查看线程的执行情况,若遇到应用进程占用cpu较多,可以通过top -p pid-H获取到是哪个线程消耗cpu较多,然后将线程id转换成十六进制,从线程栈文件找出对应的线程正在做什么,排查死锁问题,则直接查找线程栈文件,基本可以找出来大部分的死锁的问题。
jmap
排查内存溢出非常好用的工具,通过jmap可以打印出jvm堆中对象的数量及引用关系,在dump堆之后可以通过MAT或者HA分析出哪个对象实例占用较多,是否有内存泄露的情况。
jmap的用法如下:
常用的用法有:
jmap -histo:live <pid>,这种用法会强制执行一次fgc;
jmap -heap <pid>,直接打印出各对象实例的分布情况;
jmap -dump:[live],format=b,file=dump.bin <pid>,将heap dump到指定文件中
jstat
jstat在排查gc问题时真的很好用,它能够提供一些统计信息,包括gc次数,gc原因,内存占用等。还是先来看一下jstat的用法吧:
比较常用的用法有:
jstat -gcutil <pid> [interval],每隔interval(ms)打印出进程pid的gc情况;
jstat -gccause <pid> [interval],对于gcutil选项,该选项会将gc的原因列出来;
jinfo
jinfo主要用来查询jvm进程的运行时的jvm参数,以及修改jvm运行时的参数,主要用法如下:
jinfo -flag <name> <pid>,查询进程pid name的参数值;
jinfo -flag <name>=<value> <pid>,设置jvm参数name的值为value;
jinfo -flag [+|-]<name>,启用某个参数或禁用某个参数。
另外通过btrace、HSDB这些工具可以查看到应用中更为细节的东西,在排查问题的时候真的好用,谁用谁知道。
工具虽然好用,但是也只能事后帮助我们排查具体问题,在平时的编码过程过还是需要我们养成良好的编码习惯,遵循最佳实践,合理配置jvm参数,才能减少此类问题的发生。