兵器谱

jps

列出正在运行的虚拟机进程,用法如下:

jps [-option] [hostid]
选项 作用
q 只输出LVMID,省略主类的名称
m 输出main method的参数
l 输出完全的包名,应用主类名,jar的完全路径名
v 输出jvm参数

jstat

监视虚拟机运行状态信息,使用方式:

jstat -<option> <pid> [interval[s|ms]]
选项 作用
gc 输出每个堆区域的当前可用空间以及已用空间,GC执行的总次数,GC操作累计所花费的时间。
gccapactiy 输出每个堆区域的最小空间限制(ms)/最大空间限制(mx),当前大小,每个区域之上执行GC的次数。(不输出当前已用空间以及GC执行时间)。
gccause 输出-gcutil提供的信息以及最后一次执行GC的发生原因和当前所执行的GC的发生原因。
gcnew 输出新生代空间的GC性能数据。
gcnewcapacity 输出新生代空间的大小的统计数据。
gcold 输出老年代空间的GC性能数据。
gcoldcapacity 输出老年代空间的大小的统计数据。
gcpermcapacity 输出持久带空间的大小的统计数据。
gcutil 输出每个堆区域使用占比,以及GC执行的总次数和GC操作所花费的事件。

比如:

jstat -gc 28389 1s

每隔1秒输出一次JVM运行信息:

S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT
52416.0 52416.0 4744.9 0.0 419456.0 28180.6 2621440.0 439372.6 131072.0 33564.8 160472 1760.603 61 2.731 1763.334
说明 jstat参数
S0C Survivor0空间的大小。单位KB。 -gc -gccapacity -gcnew -gcnewcapacity
S1C Survivor1空间的大小。单位KB。 -gc -gccapacity -gcnew -gcnewcapacity
S0U Survivor0已用空间的大小。单位KB。 -gc -gcnew
S1U Survivor1已用空间的大小。单位KB。 -gc -gcnew
EC Eden空间的大小。单位KB。 -gc -gccapacity -gcnew -gcnewcapacity
EU Eden已用空间的大小。单位KB。 -gc-gcnew
OC 老年代空间的大小。单位KB。 -gc -gccapacity -gcold -gcoldcapacity
OU 老年代已用空间的大小。单位KB。 -gc -gcold
PC 持久代空间的大小。单位KB。 -gc -gccapacity -gcold -gcoldcapacity -gcpermcapacity
PU 持久代已用空间的大小。单位KB。 -gc -gcold
YGC 新生代空间GC时间发生的次数。 -gc -gccapacity -gcnew -gcnewcapacity -gcold -gcoldcapacity -gcpermcapacity -gcutil -gccause
YGCT 新生代GC处理花费的时间。 -gc-gcnew-gcutil-gccause
FGC full GC发生的次数。 -gc -gccapacity -gcnew -gcnewcapacity -gcold -gcoldcapacity -gcpermcapacity -gcutil -gccause
FGCT full GC操作花费的时间。 -gc -gcold -gcoldcapacity -gcpermcapacity -gcutil -gccause
GCT GC操作花费的总时间。 -gc -gcold -gcoldcapacity -gcpermcapacity -gcutil -gccause
NGCMN 新生代最小空间容量,单位KB。 -gccapacity -gcnewcapacity
NGCMX 新生代最大空间容量,单位KB。 -gccapacity -gcnewcapacity
NGC 新生代当前空间容量,单位KB。 -gccapacity -gcnewcapacity
OGCMN 老年代最小空间容量,单位KB。 -gccapacity-gcoldcapacity
OGCMX 老年代最大空间容量,单位KB。 -gccapacity-gcoldcapacity
OGC 老年代当前空间容量制,单位KB。 -gccapacity -gcoldcapacity
PGCMN 持久代最小空间容量,单位KB。 -gccapacity -gcpermcapacity
PGCMX 持久代最大空间容量,单位KB。 -gccapacity -gcpermcapacity
PGC 持久代当前空间容量,单位KB。 -gccapacity -gcpermcapacity
PC 持久代当前空间大小,单位KB。 -gccapacity-gcpermcapacity
PU 持久代当前已用空间大小,单位KB。 -gc -gcold
LGCC 最后一次GC发生的原因。 -gccause
GCC 当前GC发生的原因。 -gccause
TT 老年化阈值。被移动到老年代之前,在新生代空存活的次数。 -gcnew
MTT 最大老年化阈值。被移动到老年代之前,在新生代空存活的次数。 -gcnew
DSS 幸存者区所需空间大小,单位KB。 -gcnew

jmap

生成堆存储快照,使用方式:

jmap [ -option ] <pid>
选项 作用
dump 生成堆存储快照,格式为:-dump:[live, ]format=b, file=<filename>,live说明是否只dump出存活的对象。
heap 显示java堆详细信息,如使用那种回收器、参数配置、分代状况等。
histo 显示堆中对象统计信息,包括类、实例数量、合计容量。

jstack

生成虚拟机当前时刻的线程快照,帮助定位线程出现长时间停顿的原因,用法:

jstack <pid>

Monitor

Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者Class的锁。每一个对象都有,也仅有一个 monitor。下面这个图,描述了线程和 Monitor之间关系,以及线程的状态转换图:

进入区(Entrt Set):表示线程通过synchronized要求获取对象的锁,但并未得到。

拥有者(The Owner):表示线程成功竞争到对象锁。

等待区(Wait Set):表示线程通过对象的wait方法,释放对象的锁,并在等待区等待被唤醒。

线程状态

  • NEW,未启动的。不会出现在Dump中。
  • RUNNABLE,在虚拟机内执行的。
  • BLOCKED,等待获得监视器锁。
  • WATING,无限期等待另一个线程执行特定操作。
  • TIMED_WATING,有时限的等待另一个线程的特定操作。
  • TERMINATED,已退出的。

举个例子:

package com.jiuyan.mountain.test;

import java.util.concurrent.TimeUnit;

/**
* Hello world!
*
*/
public class App { public static void main(String[] args) throws InterruptedException {
MyTask task = new MyTask();
Thread t1 = new Thread(task);
t1.setName("t1");
Thread t2 = new Thread(task);
t2.setName("t2");
t1.start();
t2.start();
} } class MyTask implements Runnable { private Integer mutex; public MyTask() {
mutex = 1;
} @Override
public void run() {
synchronized (mutex) {
while(true) {
System.out.println(Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} }

线程状态:

"t2" prio=10 tid=0x00007f7b2013a800 nid=0x67fb waiting for monitor entry [0x00007f7b17087000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuyan.mountain.test.MyTask.run(App.java:35)
- waiting to lock <0x00000007d6b6ddb8> (a java.lang.Integer)
at java.lang.Thread.run(Thread.java:745) "t1" prio=10 tid=0x00007f7b20139000 nid=0x67fa waiting on condition [0x00007f7b17188000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)

t1没有抢到锁,所以显示BLOCKED。t2抢到了锁,但是处于睡眠中,所以显示TIMED_WAITING,有限等待某个条件来唤醒。
把睡眠的代码去掉,线程状态变成了:

"t2" prio=10 tid=0x00007fa0a8102800 nid=0x6a15 waiting for monitor entry [0x00007fa09e37a000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuyan.mountain.test.MyTask.run(App.java:35)
- waiting to lock <0x0000000784206650> (a java.lang.Integer)
at java.lang.Thread.run(Thread.java:745) "t1" prio=10 tid=0x00007fa0a8101000 nid=0x6a14 runnable [0x00007fa09e47b000]
java.lang.Thread.State: RUNNABLE
at java.io.FileOutputStream.writeBytes(Native Method)

t1显示RUNNABLE,说明正在运行,这里需要额外说明一下,如果这个线程正在查询数据库,但是数据库发生死锁,虽然线程显示在运行,实际上并没有工作,对于IO型的线程别只用线程状态来判断工作是否正常。
把MyTask的代码小改一下,线程拿到锁之后执行wait,释放锁,进入等待区。

public void run() {
synchronized (mutex) {
if(mutex == 1) {
try {
mutex.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

线程状态如下:

"t2" prio=10 tid=0x00007fc5a8112800 nid=0x5a58 in Object.wait() [0x00007fc59b58c000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method) "t1" prio=10 tid=0x00007fc5a8111000 nid=0x5a57 in Object.wait() [0x00007fc59b68d000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)

两个线程都显示WAITING,这次是无限期的,需要重新获得锁,所以后面跟了on object monitor

再来个死锁的例子:

package com.jiuyan.mountain.test;

import java.util.concurrent.TimeUnit;

/**
* Hello world!
*
*/
public class App { public static void main(String[] args) throws InterruptedException {
MyTask task1 = new MyTask(true);
MyTask task2 = new MyTask(false);
Thread t1 = new Thread(task1);
t1.setName("t1");
Thread t2 = new Thread(task2);
t2.setName("t2");
t1.start();
t2.start();
} } class MyTask implements Runnable { private boolean flag; public MyTask(boolean flag) {
this.flag = flag;
} @Override
public void run() {
if(flag) {
synchronized (Mutex.mutex1) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (Mutex.mutex2) {
System.out.println("ok");
}
}
} else {
synchronized (Mutex.mutex2) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (Mutex.mutex1) {
System.out.println("ok");
}
}
}
} } class Mutex {
public static Integer mutex1 = 1;
public static Integer mutex2 = 2;
}

线程状态:

"t2" prio=10 tid=0x00007f5f9c122800 nid=0x3874 waiting for monitor entry [0x00007f5f67efd000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuyan.mountain.test.MyTask.run(App.java:55)
- waiting to lock <0x00000007d6c45bd8> (a java.lang.Integer)
- locked <0x00000007d6c45be8> (a java.lang.Integer)
at java.lang.Thread.run(Thread.java:745) "t1" prio=10 tid=0x00007f5f9c121000 nid=0x3873 waiting for monitor entry [0x00007f5f67ffe000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuyan.mountain.test.MyTask.run(App.java:43)
- waiting to lock <0x00000007d6c45be8> (a java.lang.Integer)
- locked <0x00000007d6c45bd8> (a java.lang.Integer)
at java.lang.Thread.run(Thread.java:745) Found one Java-level deadlock:
=============================
"t2":
waiting to lock monitor 0x00007f5f780062c8 (object 0x00000007d6c45bd8, a java.lang.Integer),
which is held by "t1"
"t1":
waiting to lock monitor 0x00007f5f78004ed8 (object 0x00000007d6c45be8, a java.lang.Integer),
which is held by "t2"

这个有点像哲学家就餐问题,每个线程都持有对方需要的锁,那就运行不下去了。

调优策略

两个基本原则:

  • 将转移到老年代的对象数量降到最少。
  • 减少Full GC的执行时间。目标是Minor GC时间在100ms以内,Full GC时间在1s以内。

主要调优参数:

设定堆内存大小,这是最基本的。

  1. -Xms:启动JVM时的堆内存空间。
  2. -Xmx:堆内存最大限制。

设定新生代大小。

新生代不宜太小,否则会有大量对象涌入老年代。

  1. -XX:NewRatio:新生代和老年代的占比。
  2. -XX:NewSize:新生代空间。
  3. -XX:SurvivorRatio:伊甸园空间和幸存者空间的占比。
  4. -XX:MaxTenuringThreshold:对象进入老年代的年龄阈值。

设定垃圾回收器

年轻代:-XX:+UseParNewGC。

老年代:-XX:+UseConcMarkSweepGC。

CMS可以将STW时间降到最低,但是不对内存进行压缩,有可能出现“并行模式失败”。比如老年代空间还有300MB空间,但是一些10MB的对象无法被顺序的存储。这时候会触发压缩处理,但是CMS GC模式下的压缩处理时间要比Parallel GC长很多。

G1采用”标记-整理“算法,解决了内存碎片问题,建立了可预测的停顿时间类型,能让使用者指定在一个长度为M毫秒的时间段内,消耗在垃圾收集上的时间不得超过N毫秒。

JVM性能优化入门指南的更多相关文章

  1. 《Java性能优化权威指南》

    <Java性能优化权威指南> 基本信息 原书名:Java performance 原出版社: Addison-Wesley Professional 作者: (美)Charlie Hunt ...

  2. 读书笔记系列之java性能优化权威指南 一 第一章

    主题:java性能优化权威指南 pdf 版本:英文版 Java Performance Tuning 忽略:(0~24页)Performance+Acknowledge 1.Strategies, A ...

  3. JVM性能优化读后笔记

    java性能优化权威指南读后笔记 三重境界 1.花似雾中看:对于遇到的额问题还看不清,不知道真真假假,是是非非. 2.悠然见南山:虽然刚开始对这个领域还不清楚,但随着时间推移,你对它有许多自己的见解, ...

  4. 听说 JVM 性能优化很难?今天我小试了一把!

    文章首发于公众号「陈树义」及个人博客 shuyi.tech,欢迎关注访问. 对于 Java 开发的同学来说,JVM 性能优化可以说是比较难掌握的知识点.这不仅因为 JVM 性能优化需要掌握晦涩难懂的 ...

  5. [原创]Java性能优化权威指南读书思维导图

    [原创]Java性能优化权威指南读书思维导图 书名:Java性能优化权威指南 原书名:Java performance 作者: (美)Charlie Hunt    Binu John 译者: 柳飞 ...

  6. jvm性能优化及内存分区

     jvm性能优化及内存分区 2012-09-17 15:51:37 分类: Java Some of the default values for Sun JVMs are listed below. ...

  7. [原创]Java性能优化权威指南读书思维导图4

    [原创]Java性能优化权威指南读书思维导图4

  8. [原创]Java性能优化权威指南读书思维导图3

    [原创]Java性能优化权威指南读书思维导图3

  9. [原创]Java性能优化权威指南读书思维导图2

    [原创]Java性能优化权威指南读书思维导图2

随机推荐

  1. JSP 和 ASP.NET 谁能主宰未来【转】

    随着计算机行业的发展,以后到底谁才是 web 网站开发的主宰者呢? 1. 说说JSP.(本人工作中用的最多的就是JSP) JSP. JavaServer Pages 是Java技术的一部分,可以说是J ...

  2. [转]Windows 8.1删除这台电脑中视频/文档/下载等六个文件夹的方法

    Windows 8.1 已将“计算机”正式更名为“这台电脑”,当我们双击打开“这台电脑”后,也会很明显得发现另外一些变化:Windows 8.1  默认将视频.图片.文档.下载.音乐.桌面等常用文件夹 ...

  3. DataGridView 绑定List集合后实现自定义排序

    这里只贴主要代码,dataList是已添加数据的全局变量,绑定数据源 datagridview1.DataSource = dataList,以下是核心代码. 实现点击列表头实现自定义排序 priva ...

  4. python列表下标用法

    python中的列表下标实在太灵活了,要根据表象来分析它的内在机理,这样用起来才能溜.下标可以为负数有利有弊,好处是使用起来更简便,坏处是当我下表越界了我也不知道反倒发生奇奇怪怪的错误. print ...

  5. Android中this、super的区别

    转载:http://blog.csdn.net/dyllove98/article/details/8826232 在Java中,this通常指当前对象,super则指父类的.当你想要引用当前对象的某 ...

  6. extjs基础 使用图标字体来美化按钮)

    下载 Font Awesome 1.拷贝css 和 fonts 到build同级目录 2.需要在index.html中引入css文件 3.在main.js文件中添加 initComponent : f ...

  7. ScrollView中嵌套ListView显示

    想要ScrollView中嵌套显示ListView 需要自定义ListView 并重写onMeasure方法 重新计算  heightMeasureSpec的高度 int newHeight = Me ...

  8. Elasticsearch 权威指南

    Elasticsearch 权威指南 http://fuxiaopang.gitbooks.io/learnelasticsearch/content/index.html

  9. [转]NullPointerException异常

    原文地址:http://blog.csdn.net/javaeeteacher/article/details/4285488 顾名思义,NullPointerException是空指针异常.但是在J ...

  10. [转]session 持久化问题(重启服务器session 仍然存在)

    转:http://xiaolongfeixiang.iteye.com/blog/560800 关于在线人数统计,大都使用SessionListener监听器实现. SessionListener 触 ...