兵器谱

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. DOM 概况

    DOM(文档对象模型)是针对 HTML 和 XML 文档的一个API(应用程序编程接口).DOM 描绘了一个层次化的节点树,允许开发人员添加.移除和修改页面的某一部分. 层次节点 DOM可以将任何 H ...

  2. SQLServer(MSSQL)、MySQL、SQLite、Access相互迁移转换工具 DB2DB v1.4

    最近公司有一个项目,需要把原来的系统从 MSSQL 升迁到阿里云RDS(MySQL)上面.为便于测试,所以需要把原来系统的所有数据表以及测试数据转换到 MySQL 上面.在百度上找了很多方法,有通过微 ...

  3. Pathoto项目:AWS+golang+beego搭建

    帮兄弟写了一个网站,由于要在国外使用,选择了AWS作为服务器. 不知道后面的价格如何,12个月免费的确吸引了我. 花费3天时间,从注册到服务器搭建访问,终于搞定了.下面记录一下其中容易出错的命令. 1 ...

  4. Android系统启动分析(Init->Zygote->SystemServer->Home activity)

    整个Android系统的启动分为Linux Kernel的启动和Android系统的启动.Linux Kernel启动起来后,然后运行第一个用户程序,在Android中就是init程序. ------ ...

  5. matlab如何建立一个空矩阵,然后往里面赋值

    x=:; y=[]; :length(x) % y=[y;x(i)];%把每一个x都放到Y里,成为一列 y=[y,x(i)];%把每一个x都放到Y里,成为一行 end

  6. Service之来电监听(失败的案例)

    Service:服务,可以理解成一个运行再后台没有界面的Activity,集成于Seriver,是四大组件之一 Service的继承关系:Service-->ContextWrapper--&g ...

  7. RHCE认证考试教材

    前段时间考RHCE7,顺便给大家分享下RHCE6.7的中文教材!毕竟此书是官方的培训教材,还是值得看看!RHEL6.7承前启后的,给个赞! 下载:http://pan.baidu.com/s/1nu9 ...

  8. JS日历制作获取时间

    1.直接获取 var myDate = new Date(); myDate.getYear(); 获取当前年份(2位) myDate.getFullYear(); 获取完整的年份(4位,1970-? ...

  9. linux core dump 文件 gdb分析

    core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump. (linux中如果内存越界会收到SIG ...

  10. 转载--web前端35个jQuery小技巧!

    1. 禁止右键点击$(document).ready(function(){    $(document).bind("contextmenu",function(e){     ...