• 第八章 JVM性能监控与故障处理工具(2)


    注意:该篇博客主要记录自《深入理解java虚拟机(第二版)》

    说明:关于命令行的JVM性能监控与故障处理工具见《第七章 JVM性能监控与故障处理工具(1)

    1、图像化的故障处理工具

    • Jconsole
    • visualVM

    2、Jconsole

    进入"E:Javajdk1.6in",双击"jconsole.exe",弹出如下框:

    说明:这里列出了所有的JVM进程,一个Jconsole进程,一个eclipse(PID:4684),这相当于jps命令。

    选中其中一个PID,假设选中了eclipse,双击,出现下图:(注:之后的各个叶签,都是每4秒刷新一次

    "内存":相当于jstat -gc,在上图中的详细信息部分,该部分对应的信息就是头部图表部分所写的参数(这里是"整个堆"的情况),同时对应的也是右下角部分柱状图所选中的柱子(这里是"堆"),对于"非堆"指的就是"方法区"(或者称为"永久代")。当然,这里也可以选择时间范围来查看相应的信息。

    "类":相当于jstat -class,列出了装载类和卸载类的相关信息。

    "线程":相当于jstack,折线图显示了线程数目的变化情况,包括峰值线程数量、活动线程数量;左下角展示了所有线程名称。双击相应的线程名称

    "VM摘要":相当于jinfo

    最后,测试一下线程死锁的现象。代码如下:

     1 package thread;
     2 
     3 /**
     4  * 测试线程
     5  */
     6 class XXthread implements Runnable{
     7     int a,b;
     8     
     9     public XXthread(int a, int b) {
    10         this.a = a;
    11         this.b = b;
    12     }
    13 
    14     public void run() {
    15         synchronized (Integer.valueOf(a)) {
    16             synchronized (Integer.valueOf(b)) {
    17                 System.out.println(a + b);
    18             }
    19         }
    20     }
    21 }
    22 
    23 public class TestDeadLockThread {
    24     public static void main(String[] args) {
    25         for(int i=0;i<100;i++){
    26             new Thread(new XXthread(1, 2)).start();
    27             new Thread(new XXthread(2, 1)).start();
    28         }
    29     }
    30 }
    View Code

    执行main()方法,之后去查看"线程"标签,点击"检测死锁",如下:

    发现线程Thread-95和Thread-106死锁(彼此拥有对方想要的锁)

    分析:

    1)Integer缓存机制

    Integer.valueOf(int xxx),该方法为了减少对象的创建,节省内存,会将xxx转化成的Integer对象缓存起来,之后只要是相同的xxx,那么这个方法都会直接从缓存中取出对象来。假设代码中的Integer.valueOf(1)生成的对象是java.lang.Integer@987197,而Integer.valueOf(2)生成的对象是java.lang.Integer@15e293a,那么之后无论调用多少次Integer.valueOf(1),也无论是哪一个线程去调用该方法,返回的都只是同一个对象java.lang.Integer@987197。也就是说上边的这段代码中的Integer.valueOf(i)只会生成两个不同的对象,就是java.lang.Integer@987197和java.lang.Integer@15e293a,而这两个对象也就是我们的锁对象。

    2)死锁发生的时机

    假设线程"Thread-95"执行到其第一个synchronized块中时(假设刚刚获取了锁对象java.lang.Integer@987197),这时候CPU时间片切换给了线程"Thread-106",而"Thread-106"执行其第一个synchronized块(获取了锁对象java.lang.Integer@15e293a),之后"Thread-106"要执行第二个synchronized块儿来获取锁对象java.lang.Integer@987197,这时候就获取不到了,因为这个锁对象正被"Thread-95"所持有,于是"Thread-106"就阻塞在java.lang.Integer@987197这个锁对象上,这时,假设CPU时间片又切换给了"Thread-95",该线程要执行第二个synchronized块来获取java.lang.Integer@15e293a,就获取不到了,因为该锁对象已被"Thread-106"所持有

    3)结果

    "Thread-95"持有锁对象java.lang.Integer@987197,阻塞在锁对象java.lang.Integer@15e293a;

    "Thread-106"持有锁对象java.lang.Integer@15e293a,阻塞在锁对象java.lang.Integer@987197

    3、visualVM

    是一块更加全面的GUI监视工具,包含很多插件(需要自己下载),具体的见《深入理解Java虚拟机(第二版)》

  • 相关阅读:
    Git Merge Request
    Hazelcast Hazelcast介绍与使用
    Git 修改name/author信息
    HDU 2553 N皇后问题(DFS)
    HDU 1070 Milk(水题)
    HDU 2616 Kill the monster(简单DFS)
    HDU 1426 Sudoku Killer(BFS)
    HDU 2216 Game III(BFS)
    URAL 1001 Reverse Root(水题)
    URAL 1902 NeoVenice(水题)
  • 原文地址:https://www.cnblogs.com/java-zhao/p/5185005.html
Copyright © 2020-2023  润新知