JDK内置工具使用-jstack命令(Java Stack Trace)

1、介绍

jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项”-J-d64″,Windows的jstack使用方式只支持以下的这种方式:

jstack [-l] pid

如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。

2、命令格式
jstack [ option ] pid
jstack [ option ] executable core
jstack [ option ] [server-id@]remote-hostname-or-IP

3、常用参数说明

1)、options: 

executable Java executable from which the core dump was produced.

(可能是产生core dump的java可执行程序)

core 将被打印信息的core dump文件

remote-hostname-or-IP 远程debug服务的主机名或ip

server-id 唯一id,假如一台主机上多个远程debug服务 

2)、基本参数:

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

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

-m打印java和native c/c++框架的所有栈信息.

-h | -help打印帮助信息

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

4、使用示例

转自:csdn-jstack命令

JDK内置工具使用-jmap命令(Java Memory Map)

1、介绍

打印出某个java进程(使用pid)内存内的,所有‘对象’的情况(如:产生那些对象,及其数量)。

可以输出所有内存中对象的工具,甚至可以将VM 中的heap,以二进制输出成文本。使用方法 jmap -histo pid。如果连用SHELL jmap -histo pid>a.log可以将其保存到文本中去,在一段时间后,使用文本对比工具,可以对比出GC回收了哪些对象。jmap -dump:format=b,file=outfile 3024可以将3024进程的内存heap输出出来到outfile文件里,再配合MAT(内存分析工具(Memory Analysis Tool),使用参见:http://blog.csdn.net/fenglibing/archive/2011/04/02/6298326.aspx)或与jhat (Java Heap Analysis Tool)一起使用,能够以图像的形式直观的展示当前内存是否有问题。

64位机上使用需要使用如下方式:

jmap -J-d64 -heap pid

2、命令格式

SYNOPSIS

       jmap [ option ] pid

       jmap [ option ] executable core

       jmap [ option ] [server-id@]remote-hostname-or-IP

3、参数说明

1)、options: 

executable Java executable from which the core dump was produced.

(可能是产生core dump的java可执行程序)

core 将被打印信息的core dump文件

remote-hostname-or-IP 远程debug服务的主机名或ip

server-id 唯一id,假如一台主机上多个远程debug服务 

2)、基本参数:

-dump:[live,]format=b,file= 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件. 

-finalizerinfo 打印正等候回收的对象的信息.

-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况.

-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量. 

-permstat 打印classload和jvm heap长久层的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来. 

-F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效. 

-h | -help 打印辅助信息 

-J 传递参数给jmap启动的jvm. 

pid 需要被打印配相信息的java进程id,创业与打工的区别 – 博文预览,可以用jps查问.

4、使用示例

1)、[fenglb@ccbu-156-5 ~]$ jmap -histo 4939

[输出较多这里不贴了]

2)、[fenglb@ccbu-156-5 ~]$ jmap -dump:format=b,file=test.bin 4939

Dumping heap to /home/fenglb/test.bin …

Heap dump file created

转自:CSDN-jmap命令(Java Memory Map)

JVM内置工具-jstat命令(Java Virtual Machine Statistics Monitoring Tool)

1、介绍

Jstat用于监控基于HotSpot的JVM,对其堆的使用情况进行实时的命令行的统计,使用jstat我们可以对指定的JVM做如下监控:

– 类的加载及卸载情况

– 查看新生代、老生代及持久代的容量及使用情况

– 查看新生代、老生代及持久代的垃圾收集情况,包括垃圾回收的次数及垃圾回收所占用的时间

– 查看新生代中Eden区及Survior区中容量及分配情况等

jstat工具特别强大,它有众多的可选项,通过提供多种不同的监控维度,使我们可以从不同的维度来了解到当前JVM堆的使用情况。详细查看堆内各个部分的使用量,使用的时候必须加上待统计的Java进程号,可选的不同维度参数以及可选的统计频率参数。

它主要是用来显示GC及PermGen相关的信息,如果对GC不怎么了解,先看这篇文章:http://blog.csdn.net/fenglibing/archive/2011/04/13/6321453.aspx,否则其中即使你会使用jstat这个命令,你也看不懂它的输出。

 2、语法

     jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]

    generalOption – 单个的常用的命令行选项,如-help, -options, 或 -version。

    outputOptions –一个或多个输出选项,由单个的statOption选项组成,可以和-t, -h, and -J等选项配合使用。

    statOption

    根据jstat统计的维度不同,可以使用如下表中的选项进行不同维度的统计,不同的操作系统支持的选项可能会不一样,可以通过-options选项,查看不同操作系统所支持选项,如:

OptionDisplays…
class用于查看类加载情况的统计
compiler用于查看HotSpot中即时编译器编译情况的统计
gc用于查看JVM中堆的垃圾收集情况的统计
gccapacity用于查看新生代、老生代及持久代的存储容量情况
gccause用于查看垃圾收集的统计情况(这个和-gcutil选项一样),如果有发生垃圾收集,它还会显示最后一次及当前正在发生垃圾收集的原因。
gcnew用于查看新生代垃圾收集的情况
gcnewcapacity用于查看新生代的存储容量情况
gcold用于查看老生代及持久代发生GC的情况
gcoldcapacity用于查看老生代的容量
gcpermcapacity用于查看持久代的容量
gcutil用于查看新生代、老生代及持代垃圾收集的情况
printcompilationHotSpot编译方法的统计

    -h n

        用于指定每隔几行就输出列头,如果不指定,默认是只在第一行出现列头。

    -JjavaOption

        用于将给定的javaOption传给java应用程序加载器,例如,“-J-Xms48m”将把启动内存设置为48M。如果想查看可以传递哪些选项到应用程序加载器中,可以相看如下的文档:

        Linux and Solaris:http://docs.oracle.com/javase/1.5.0/docs/tooldocs/solaris/java.html

        Windows: http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/java.html

    -t n

        用于在输出内容的第一列显示时间戳,这个时间戳代表的时JVM开始启动到现在的时间(注:在IBM JDK5中是没有这个选项的)。

    vmid  – VM的进程号,即当前运行的java进程号。

    还有两个关于显示频率的选项:

    interval–间隔时间,单位可以是秒或者毫秒,通过指定s或ms确定,默认单位为毫秒。

    count-打印次数,如果缺省则打印无数次。

3、不同的统计维度(statOption)及输出说明

    -class

列名说明
Loaded加载了的类的数量
Bytes加载了的类的大小,单为Kb
Unloaded卸载了的类的数量
Bytes卸载了的类的大小,单为Kb
Time花在类的加载及卸载的时间

     -compiler

列名说明
Compiled编译任务执行的次数
Failed编译任务执行失败的次数
Invalid编译任务非法执行的次数
Time执行编译花费的时间
FailedType最后一次编译失败的编译类型
FailedMethod最后一次编译失败的类名及方法名

     -gc

列名说明
S0C新生代中Survivor space中S0当前容量的大小(KB)
S1C新生代中Survivor space中S1当前容量的大小(KB)
S0U新生代中Survivor space中S0容量使用的大小(KB)
S1U新生代中Survivor space中S1容量使用的大小(KB)
ECEden space当前容量的大小(KB)
EUEden space容量使用的大小(KB)
OCOld space当前容量的大小(KB)
OUOld space使用容量的大小(KB)
PCPermanent space当前容量的大小(KB)
PUPermanent space使用容量的大小(KB)
YGC从应用程序启动到采样时发生 Young GC 的次数
YGCT从应用程序启动到采样时 Young GC 所用的时间(秒)
FGC从应用程序启动到采样时发生 Full GC 的次数
FGCT从应用程序启动到采样时 Full GC 所用的时间(秒)
GCTT从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC

    -gccapacity

列名说明
NGCMN新生代的最小容量大小(KB)
NGCMX新生代的最大容量大小(KB)
NGC当前新生代的容量大小(KB)
S0C当前新生代中survivor space 0的容量大小(KB)
S1C当前新生代中survivor space 1的容量大小(KB)
ECEden space当前容量的大小(KB)
OGCMN老生代的最小容量大小(KB)
OGCMX老生代的最大容量大小(KB)
OGC当前老生代的容量大小(KB)
OC当前老生代的空间容量大小(KB)
PGCMN持久代的最小容量大小(KB)
PGCMX持久代的最大容量大小(KB)
PGC当前持久代的容量大小(KB)
PC当前持久代的空间容量大小(KB)
YGC从应用程序启动到采样时发生 Young GC 的次数
FGC从应用程序启动到采样时发生 Full GC 的次数

    -gccause

     这个选项用于查看垃圾收集的统计情况(这个和-gcutil选项一样),如果有发生垃圾收集,它还会显示最后一次及当前正在发生垃圾收集的原因,它比-gcutil会多出最后一次垃圾收集原因以及当前正在发生的垃圾收集的原因。

列名说明
LGCC最后一次垃圾收集的原因,可能为“unknown GCCause”、“System.gc()”等
GCC当前垃圾收集的原因

    -gcnew

列名说明
S0C当前新生代中survivor space 0的容量大小(KB)
S1C当前新生代中survivor space 1的容量大小(KB)
S0US0已经使用的大小(KB)
S1US1已经使用的大小(KB)
TTTenuring threshold,要了解这个参数,我们需要了解一点Java内存对象的结构,在Sun JVM中,(除了数组之外的)对象都有两个机器字(words)的头部。第一个字中包含这个对象的标示哈希码以及其他一些类似锁状态和等标识信息,第二个字中包含一个指向对象的类的引用,其中第二个字节就会被垃圾收集算法使用到。
在新生代中做垃圾收集的时候,每次复制一个对象后,将增加这个对象的收集计数,当一个对象在新生代中被复制了一定次数后,该算法即判定该对象是长周期的对象,把他移动到老生代,这个阈值叫着tenuring threshold。这个阈值用于表示某个/些在执行批定次数youngGC后还活着的对象,即使此时新生的的Survior没有满,也同样被认为是长周期对象,将会被移到老生代中。
MTTMaximum tenuring threshold,用于表示TT的最大值。
DSSDesired survivor size (KB).可以参与这里:http://blog.csdn.net/yangjun2/article/details/6542357
ECEden space当前容量的大小(KB)
EUEden space已经使用的大小(KB)
YGC从应用程序启动到采样时发生 Young GC 的次数
YGCT从应用程序启动到采样时 Young GC 所用的时间(单位秒)

    -gcnewcapacity

列名说明
NGCMN          新生代的最小容量大小(KB)
NGCMX    新生代的最大容量大小(KB)
NGC    当前新生代的容量大小(KB)
S0CMX新生代中SO的最大容量大小(KB)
S0C当前新生代中SO的容量大小(KB)
S1CMX新生代中S1的最大容量大小(KB)
S1C当前新生代中S1的容量大小(KB)
ECMX新生代中Eden的最大容量大小(KB)
EC当前新生代中Eden的容量大小(KB)
YGC从应用程序启动到采样时发生 Young GC 的次数
FGC从应用程序启动到采样时发生 Full GC 的次数

    -gcold

列名说明
PC当前持久代容量的大小(KB)
PU持久代使用容量的大小(KB)
OC当前老年代容量的大小(KB)
OU老年代使用容量的大小(KB)
YGC从应用程序启动到采样时发生 Young GC 的次数
FGC从应用程序启动到采样时发生 Full GC 的次数
FGCT从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC

    -gcoldcapacity

列名说明
OGCMN老生代的最小容量大小(KB)
OGCMX老生代的最大容量大小(KB)
OGC当前老生代的容量大小KB)
OC当前新生代的空间容量大小KB)
YGC从应用程序启动到采样时发生 Young GC 的次数
FGC从应用程序启动到采样时发生 Full GC 的次数
FGCT从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC

    -gcpermcapacity

    从应用程序启动到采样时发生 Full GC 的次数

列名说明
PGCMN持久代的最小容量大小(KB)
PGCMX持久代的最大容量大小(KB)
PGC当前持久代的容量大小KB)
PC当前持久代的空间容量大小KB)
YGC从应用程序启动到采样时发生 Young GC 的次数
FGC
FGCT从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC

    -gcutil

列名说明
S0Heap上的 Survivor space 0 区已使用空间的百分比
S1Heap上的 Survivor space 1 区已使用空间的百分比
EHeap上的 Eden space 区已使用空间的百分比
OHeap上的 Old space 区已使用空间的百分比
PPerm space 区已使用空间的百分比
YGC从应用程序启动到采样时发生 Young GC 的次数
YGCT从应用程序启动到采样时 Young GC 所用的时间(单位秒)
FGC从应用程序启动到采样时发生 Full GC 的次数
FGCT从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC

    -printcompilation

列名说明
Compiled编译任务执行的次数
Size方法的字节码所占的字节数
Type编译类型
Method指定确定被编译方法的类名及方法名,类名中使名“/”而不是“.”做为命名分隔符,方法名是被指定的类中的方法,这两个字段的格式是由HotSpot中的“-XX:+PrintComplation”选项确定的。

4、使用示例

示例1)、

示例2):

图中同时打印了young gc和full gc的总次数、总耗时。而,每次young gc消耗的时间,可以用相间隔的两行YGCT相减得到。每次full gc消耗的时间,可以用相隔的两行FGCT相减得到。例如红框中表示的第一行、第二行之间发生了1次young gc,消耗的时间为0.252-0.252=0.0秒。

常驻内存区(P)的使用率,始终停留在64.21%左右,说明常驻内存没有突变,比较正常。如果young gc和full gc能够正常发生,而且都能有效回收内存,常驻内存区变化不明显,则说明java内存释放情况正常,垃圾回收及时,java内存泄露的几率就会大大降低。但也不能说明一定没有内存泄露。

示例3)、

    以上,介绍了Jstat按百分比查看gc情况的功能。其实,它还有功能,例如加载类信息统计功能、内存池信息统计功能等,那些是以绝对值的形式打印出来的,比较少用,在此就不做介绍。

示例4)、jstat -class pid:显示加载class的数量,及所占空间等信息。

 示例5)、jstat -compiler pid:显示VM实时编译的数量等信息。

示例6)、查看远程服务器上的GC情况。

    这个需要先在远程服务器上面开启jstatd服务,可以选看这里如何开启jstatd服务,http://blog.csdn.net/fenglibing/article/details/17323515

    下面是一个执行示例:

C:\Documents and Settings\Administrator>jstat -gcutil 18272@the_ip:2021/jstatdName 1000

  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT
  0.00   0.00   8.00   0.00  24.36      0    0.000     0    0.000    0.000
  0.00   0.00   8.00   0.00  24.36      0    0.000     0    0.000    0.000
  0.00   0.00   8.00   0.00  24.36      0    0.000     0    0.000    0.000
  0.00   0.00   8.00   0.00  24.36      0    0.000     0    0.000    0.000
  0.00   0.00   8.00   0.00  24.36      0    0.000     0    0.000    0.000
  0.00   0.00   8.00   0.00  24.36      0    0.000     0    0.000    0.000

    示例就不一一例举,有兴趣的可以自己尝试尝试。


Oracle上关于Jstat的使用说明:http://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jstat.html

转自: CSDN-jstat命令(Java Virtual Machine Statistics Monitoring Tool)

jvm CPU飚高 查询java线程

1,根据top命令,找到占用CPU高的进程的PID,比如2633。

2,找出该进程内最耗费CPU的线程,可以使用

1)ps -Lfp pid

2)ps -mp pid -o THREAD, tid, time

3)top -Hp pid

这里用第三个,输出如下:

TIME列就是各个Java线程耗费的CPU时间,CPU时间最长的是线程ID为21742的线程,用

printf "%x\n" 21742

得到21742的十六进制值为54ee,下面会用到。

3. 下一步轮到jstack上场了,它用来输出进程21711的堆栈信息,然后根据线程ID的十六进制值grep,如下:

jstack 2633 |grep 54ee -A 30
"PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait()

可以看到CPU消耗在PollIntervalRetrySchedulerThread这个类的Object.wait(),我找了下我的代码,定位到下面的代码:

// Idle wait
getLog().info("Thread [" + getName() + "] is idle waiting..."); schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting; long now = System.currentTimeMillis(); long waitTime = now + getIdleWaitTime(); long timeUntilContinue = waitTime - now; synchronized(sigLock) {  try {   if(!halted.get()) {    sigLock.wait(timeUntilContinue);   }  }  catch (InterruptedException ignore) {  } }

它是轮询任务的空闲等待代码,上面的sigLock.wait(timeUntilContinue)就对应了前面的Object.wait()。

JDK8 tomcat启动时SecureRandom 非常慢解决办法

转:jdk8 tomcat启动很慢的问题

JDK8+tomcat8环境tomcat启动时SecureRandom 非常慢解决办法

 

JDK 8 + tomcat8 启动有时会出现 org.apache.catalina.util.SessionIdGeneratorBase- Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [413,255] milliseconds
耗时时间很长。
Tomcat 8启动很慢,且日志上无任何错误,在日志中查看到如下信息:
Log4j:[2015-10-29 15:47:11] INFO ReadProperty:172 – Loading properties file from class path resource [resources/jdbc.properties]
Log4j:[2015-10-29 15:47:11] INFO ReadProperty:172 – Loading properties file from class path resource [resources/common.properties]
29-Oct-2015 15:52:53.587 INFO [localhost-startStop-1] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [342,445] milliseconds.
原因

Tomcat 7/8都使用org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom类产生安全随机类SecureRandom的实例作为会话ID,这里花去了342秒,也即接近6分钟。

SHA1PRNG算法是基于SHA-1算法实现且保密性较强的伪随机数生成器。

在SHA1PRNG中,有一个种子产生器,它根据配置执行各种操作。

1)如果Java.security.egd 属性或securerandom.source属性指定的是”file:/dev/random”或”file:/dev/urandom”,那么JVM 会使用本地种子产生器NativeSeedGenerator,它会调用super()方法,即调用 SeedGenerator.URLSeedGenerator(/dev/random)方法进行初始化。

2)如果java.security.egd属性或securerandom.source属性指定的是其它已存在的URL,那么会调用SeedGenerator.URLSeedGenerator(url)方法进行初始化。

这就是为什么我们设置值为”file:///dev/urandom”或者值为”file:/./dev/random”都会起作用的原因。

在这个实现中,产生器会评估熵池(entropy pool)中的噪声数量。随机数是从熵池中进行创建的。当读操作时,/dev/random设备会只返回熵池中噪声的随机字节。/dev/random非 常适合那些需要非常高质量随机性的场景,比如一次性的支付或生成密钥的场景。

当熵池为空时,来自/dev/random的读操作将被阻塞,直到熵池收集到足够的环境噪声数据。这么做的目的是成为一个密码安全的伪随机数发生器,熵池要有尽可能大的输出。对于生成高质量的加密密钥或者是需要长期保护的场景,一定要这么做。

那么什么是环境噪声?

随机数产生器会手机来自设备驱动器和其它源的环境噪声数据,并放入熵池中。产生器会评估熵池中的噪声数据的数量。当熵池为空时,这个噪声数据的收集是比较花时间的。这就意味着,Tomcat在生产环境中使用熵池时,会被阻塞较长的时间。

解决

有两种解决办法:

1)在Tomcat环境中解决

可以通过配置JRE使用非阻塞的Entropy Source。

在catalina.sh中加入这么一行:-Djava.security.egd=file:/dev/./urandom 即可。

加入后再启动Tomcat,整个启动耗时下降到Server startup in 2912 ms。
2)在JVM环境中解决

打开$JAVA_PATH/jre/lib/security/java.security这个文件,找到下面的内容:

securerandom.source=file:/dev/urandom
替换成

securerandom.source=file:/dev/./urandom
经测试:在JVM环境中解决比较有效。