使用jdk的jps、jstack工具检测代码问题,提高程序性能

??

今天给大家分享怎样利用jdk的jps和jstack工具结合定位代码的问题,提高程序的稳定性、健壮性和性能。

在jdk的bin,目录下面有很多的工具如图:

jps、jstack工具介绍:


jps:

是JDK1.5提供的一个显示当前所有java进程pid的命令,简单实用,非常适合在linux/unix平台上简单察看当前java进程的一些简单情况。

命令格式:jps [options ] [ hostid ]

[options]选项 :

-q:仅输出VM标识符,不包括classname,jar name,arguments in main method

-m:输出main method的参数

-l:输出完全的包名,应用主类名,jar的完全路径名

-v:输出jvm参数

-V:输出通过flag文件传递到JVM中的参数(.hotspotrc文件或-XX:Flags=所指定的文件

-Joption:传递参数到vm,例如:-J-Xms1024m

用-l作示例:

在图中,第一例是进程号,第二例是进程名(运行的程序),比如activemq(/home/activeMq/apache-activemq-5.5.1/bin/run.jar)、dubbo

服务(com.alibaba.dubbo.container.Main)、tomcat(org.apache.catalina.startup.Bootstrap)等等。

jstack:


jstack是java虚拟机自带的一种堆栈跟踪工具。jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正

在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时

间等待等。

线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

命令格式:jstack [ option ] pid

[options]选项 :

-F :当’jstack [-l] pid’没有响应的时候强制打印栈信息;

-l :长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.

-m: 打印java和native c/c++框架的所有栈信息. -h | -help打印帮助信息

pid :需要被打印配置信息的java进程id,可以用jps工具查询

用-l作示例:

命令:

运行结果:

从图中我们可以查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

jps、jstack查找代码问题

原理:


通过jps命令查找到对应程序的进程,记录进程号,通过jstack命令把该进程号所在的程序的线程堆栈信息输出到文件,然后对文件里面的信息进行

分析,找到原因并解决问题。

:这种方式尽量在并发的时候进行使用这样更容易找出代码问题。

步骤:

1).进入到jdk的bin目录,如图:

2).使用jps工具查看tomcat的进程(如果是linux环境建议使用ps命令);

因为只安装了一个tomcat,使用jps -m命令(如果安装了多个tomcat ,请使用jps -v命令,该命令运行的结果中可以看到各个tomcat的路径)

3).执行jstack命令,并把输出结果输出到日志文件;

命令:

[[email protected] bin]# jstack 28501 >log1.log

打开文件log1.log文件看里面内容:

[[email protected] bin]# tail -200f log1.log
        - locked <0x00000007058fc4b0> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:484)
        at java.lang.Thread.run(Thread.java:662)

"http-8090-11" daemon prio=10 tid=0x00002aaab4047000 nid=0x7181 in Object.wait() [0x000000004238b000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000007056433f0> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at java.lang.Object.wait(Object.java:485)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:458)
        - locked <0x00000007056433f0> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:484)
        at java.lang.Thread.run(Thread.java:662)

"http-8090-10" daemon prio=10 tid=0x00002aaab46ec000 nid=0x7180 in Object.wait() [0x000000004228a000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x0000000705643610> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at java.lang.Object.wait(Object.java:485)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:458)
        - locked <0x0000000705643610> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:484)
        at java.lang.Thread.run(Thread.java:662)

"http-8090-9" daemon prio=10 tid=0x00002aaab4525800 nid=0x717f in Object.wait() [0x000000004078a000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x0000000705643898> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at java.lang.Object.wait(Object.java:485)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:458)
        - locked <0x0000000705643898> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:484)
        at java.lang.Thread.run(Thread.java:662)

4).日志文件进行分析

由于上面的tomcat没有进行压力测试,所以看到的都是tomcat的线程没有自己程序代码的线程。因此使用前段时间的进过

压力测试后导出的日志进行分析。部分日志内容如下:

"DubboClientHandler-192.168.6.162:2099-thread-2" daemon prio=10 tid=0x00002aaac069a000 nid=0x14c1 waiting on condition [0x000000004867f000]
   java.lang.Thread.State: TIMED_WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x0000000782c4d8e0> (a java.util.concurrent.SynchronousQueue$TransferStack)
	at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)
	at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424)
	at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323)
	at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
	at java.lang.Thread.run(Thread.java:662)

"DubboClientHandler-192.168.6.162:2099-thread-2" daemon prio=10 tid=0x000000005be86000 nid=0x14c0 waiting on condition [0x000000004863e000]
   java.lang.Thread.State: TIMED_WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x0000000782c61ac0> (a java.util.concurrent.SynchronousQueue$TransferStack)
	at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)
	at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424)
	at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323)
	at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
	at java.lang.Thread.run(Thread.java:662)

"http-portal%2F192.168.6.162-8097-184" daemon prio=10 tid=0x00002aaab0ecc800 nid=0x2d7a waiting for monitor entry [0x0000000045fa9000]
  java.lang.Thread.State: BLOCKED (on object monitor)
    at org.apache.log4j.Category.callAppenders(Category.java:204)
    - waiting to lock <0x00000007800020a0> (a org.apache.log4j.spi.RootLogger)
    at org.apache.log4j.Category.forcedLog(Category.java:391)
    at org.apache.log4j.Category.log(Category.java:856)
    at org.slf4j.impl.Log4jLoggerAdapter.info(Log4jLoggerAdapter.java:304)

从最后的日志中我们可以看出这个日志线程处于BLOCKED状态,进入org.apache.log4j.Category类的callAppenders方法,

代码如下:

/**
     Call the appenders in the hierrachy starting at
     <code>this</code>.  If no appenders could be found, emit a
     warning.

     <p>This method calls all the appenders inherited from the
     hierarchy circumventing any evaluation of whether to log or not
     to log the particular log request.

     @param event the event to log.
*/
  public void callAppenders(LoggingEvent event) {
    int writes = 0;

    for(Category c = this; c != null; c=c.parent) {
      // Protected against simultaneous call to addAppender, removeAppender,...
      synchronized(c) {
	if(c.aai != null) {
	  writes += c.aai.appendLoopOnAppenders(event);
	}
	if(!c.additive) {
	  break;
	}
      }
    }

    if(writes == 0) {
      repository.emitNoAppenderWarning(this);
    }
  }

从上面可以看出在该方法中有synchronized同步锁,同步锁会导致线程竞争,那么在大并发情况下将会出现性能问题,同时

会引起线程BLOCKED问题。

可以使用Apache log 解决这个问题,代码如下:

private static final Log log = LogFactory.getLog("xxx");  

通过测试,org.apache.log4j.Category.callAppenders线程BLOCKED问题没有了。

上面只是一个非常简单的示例,现实开发过程中可以根据线程的状态能够找出很多问题。大家不妨尝试一下。

---------------------------------------------------------------------------版权声明------------------------------------------------------------------------------------------

版权声明:本文为博主原创文章,未经博主允许不得转载。博客地址:http://blog.csdn.net/mr_smile2014

时间: 2024-08-04 10:20:50

使用jdk的jps、jstack工具检测代码问题,提高程序性能的相关文章

一小时写给同组的如何使用工具检测代码质量

因为要做个小项目,同组的同事都比较年轻,为了规范下代码,因此简单的写了下怎么提高代码质量,分享一下: 在接口不通的情况下进行单元测试 使用Mockito, 如果获取余额部分代码为: public class PayServiceImpl implements PayService { private BizPayService bizPayService; @Override public BigDecimal getBalance(String pin) { try { return bizP

JVM 性能调优实战之:使用阿里开源工具 TProfiler 在海量业务代码中精确定位性能代码

本文是<JVM 性能调优实战之:一次系统性能瓶颈的寻找过程> 的后续篇,该篇介绍了如何使用 JDK 自身提供的工具进行 JVM 调优将 TPS 由 2.5 提升到 20 (提升了 7 倍),并准确定位系统瓶颈:我们应用里静态对象不是太多.有大量的业务线程在频繁创建一些生命周期很长的临时对象,代码里有问题.那么问题来了,如何在海量业务代码里边准确定位这些性能代码?本文将介绍如何使用阿里开源工具 TProfiler 来定位这些性能代码,成功解决掉了 GC 过于频繁的性能瓶颈,并最终在上次优化的基础

JDK的命令行工具系列 (二) javap、jinfo、jmap

javap: 反编译工具, 可用来查看java编译器生成的字节码 参数摘要: -help 帮助 -l 输出行和变量的表 -public 只输出public方法和域 -protected 只输出public和protected类和成员 -package 只输出包,public和protected类和成员,这是默认的 -p -private 输出所有类和成员 -s 输出内部类型签名 -c 输出分解后的代码,例如,类中每一个方法内,包含java字节码的指令 -verbose 输出栈大小,方法参数的个数

jconsole工具检测堆内存变化的使用

jconsole将Java写的程序检测. 从Java 5开始 引入了 JConsole.JConsole 是一个内置 Java 性能分析器,可以从命令行或在 GUI shell 中运行.您可以轻松地使用 JConsole(或者,它更高端的 "近亲" VisualVM )来监控 Java 应用程序性能和跟踪 Java 中的代码. 如果是从命令行启动,使 JDK 在 PATH 上,运行 jconsole 即可. 如果从 GUI shell 启动,找到 JDK 安装路径,打开 bin 文件夹

安装并使用CheckStyle/PMD与FindBug &amp;&amp; 安装并使用SourceMonitor检测代码复杂度

一.安装并使用CheckStyle  (一)安装 (1) 首先从官网上下载net.sf.eclipsecs-updatesite_6.5.0.201504121610-bin 并解压chekstyle中的文件. (2)然后解压checkstyle文件中的压缩文件,将里面的两个文件夹plugins和 features下面的文件分别拷贝到eclipse目录下面对应的plugins和features目录,重启eclipse. (3)Eclipse中,选择Windows->Preferences->c

Linux下c++程序内存泄漏检测代码范例

Linux下对于程序内存泄漏检测的方法很多,最常用的的莫过于使用valgrind工具.但是valgrind相当于让程序在虚拟机中运行,会带来较大的系统资源开销,还会对程序的运行效率产生较大影响,对于那种资源占用大的程序,如果需要长时间运行才能暴露的泄漏问题,它就显得不太好用. linux下的c++程序中自己实现一个轻量级的泄漏检测代码其实是比较方便的,下面我就给出一个简单的范例,并作简单的说明.当然,我们还是应该提倡使用共享指针,用共享指针自动管理内存可以避免内存泄漏这样的不必要的麻烦. 基本原

Python-OpenCV人脸检测(代码)

Python-OpenCV人脸检测(代码) @author:wepon @blog:http://blog.csdn.net/u012162613/article/details/43523507 做人脸识别,首先要检测出图片/视频中的人脸,今天就研究了一下OpenCV的Python接口,把常用的一些功能模块写成函数.基于Python-OpenCV以及PIL,实现图片中人脸的检测以及截取保存.眼睛检测.笑脸检测.下面简单总结一下. 一.软件安装 安装Python-OpenCV以及其依赖库.PIL

Python,django:用line_profiler工具分析代码的性能

昨天下班前写了一段后端程序,然后运行后,发现网页打开速度有点慢,不太理想(因为要去后台数据库进行大量数据查询,而且还要进行运算,所以速度有点慢),然后想到有没有专业的工具对代码块进行性能分析呢?之前一直都是用datetime模块来分析,实例如下: #coding=utf-8 import datetime def f(x,y):     t1 = datetime.datetime.now()     a = x + y     t2 = datetime.datetime.now()     

堆栈 Cookie 检测代码检测到基于堆栈的缓冲区溢出

 报错:0x000CC3C9 处有未经处理的异常(在 image_opencv2.exe 中):  堆栈 Cookie 检测代码检测到基于堆栈的缓冲区溢出. 主要检查代码中有没有对数组的越界操作,就解决了这个bug. 其它的相关知识查后再补充.