zoukankan      html  css  js  c++  java
  • 《深入理解Java虚拟机》:JVM高级特性与最佳实践(第3 版)4.3.1 JHSDB:基于服务性代理的调试工具 (笔记随录)

    根据这一章节的代码,给出jdk8(默认Parallel Scavenge + Parallel Old垃圾收集器)的JHSDB截图。

    写这个随笔,主要方便自己的github笔记有图片(不想直接上传图片到github,那样下次clone太慢了)

    1. java代码如下(来自书籍)

    /**
    * staticObj、instanceObj、localObj存放在哪里?
    */
    public class JHSDB_TestCase {
      static class Test {
        static ObjectHolder staticObj = new ObjectHolder();
        ObjectHolder instanceObj = new ObjectHolder();
        void foo() {
          ObjectHolder localObj = new ObjectHolder();
          System.out.println("done"); // 这里设一个断点
        }
      }
      private static class ObjectHolder {}
      public static void main(String[] args) {
        Test test = new JHSDB_TestCase.Test();
        test.foo();
      }
    }
    

    上述代码,理论上:

    • staticObj随着Test的类型信息存放在方法区
    • instanceObj随着Test的对象实例存放在Java堆
    • localObject则是存放在foo()方法栈帧的局部变量表中

    下面使用JHSDB工具做验证

    2. 根据书本建议,启动JVM时指定参数如下:

    -Xmx10m -XX:+UseSerialGC -XX:-UseCompressedOops
    

    3. JPS查看LVMID(通常==PID)

    这里 1587 就是我要的

    $ jps                  
    2216 Launcher
    2218 JHSDB_TestCase
    2219 Jps
    1247
    

    4. JHSDB图形化模式,附加到java进程

    $ jhsdb hsdb --pid 2218
    

    输入上述指令后,出现图形化界面如下:

    5. 验证对象所在区域

    使用scanoops命令在Java堆的新生代(从Eden起始地址到To Survivor结束地址)范围内查找ObjectHolder的实例。

    下述指令在新出现的Console窗口里输入,并得到结果(和网上一篇CSDN的博客一样。我这里也是获取不到对象)

    scanoops 0x000000010dc00000 0x000000010df00000 JHSDB_TestCase$ObjectHolder
    No such type.
    

    只好用另一个方法,查询 对象所在之处

    双击 "gc.JHSDB_TestCase$ObjectHolder"

    上图,验证了一般情况下新对象在Eden中创建的分配规则。

    使用Tools->Inspector功能确认一下这三个地址中存放的对象

    (下述文字是该书的原话)
    Inspector为我们展示了对象头和指向对象元数据的指针,里面包括了Java类型的名字、继承关系、实现接口关系,
    字段信息、方法信息、运行时常量池的指针、内嵌的虚方法表(vtable)以及接口方法表(itable)等
    由于我们的确没有在ObjectHolder上定义过任何字段,所以图中并没有看到任何实例字段数据。

    接下来要根据堆中对象实例地址找出引用它们的指针,原本JHSDB的Tools菜单中有Compute
    Reverse Ptrs来完成这个功能,但在笔者的运行环境中一点击它就出现Swing的界面异常,看后台日志是
    报了个空指针,这个问题只是界面层的异常,跟虚拟机关系不大,所以笔者(书籍的作者)没有继续去深究,改为使
    用命令来做也很简单,先拿第一个对象来试试看:

    revptrs 0x000000010dc532b0
    null
    Oop for java/lang/Class @ 0x000000010dc519a8
    hsdb> 
    

    根据查询到的堆中对象的地址,回去查指向堆中对象的指针(发现是个java.lang.Class类型的对象实例staticObj)

    从《Java虚拟机规范》所定义的概念模型来看,所有Class相关的信息都应该存放在方法区之中,
    但方法区该如何实现,《Java虚拟机规范》并未做出规定,这就成了一件允许不同虚拟机自己灵活把
    握的事情。JDK 7及其以后版本的HotSpot虚拟机选择把静态变量与类型在Java语言一端的映射Class对
    象存放在一起,存储于Java堆之中,从我们的实验中也明确验证了这一点

    这次找到一个类型为JHSDB_TestCase$Test的对象实例

    这个结果完全符合我们的预期,第二个ObjectHolder的指针是在Java堆中JHSDB_TestCase$Test对象的instanceObj字段上。

    但是我们采用相同方法查找第三个ObjectHolder实例时,JHSDB返回了一个null,表示未查找到任何结果:

    看来revptrs命令并不支持查找栈上的指针引用,不过没有关系,得益于我们测试代码足够简洁,
    人工也可以来完成这件事情。在Java Thread窗口选中main线程后点击Stack Memory按钮查看该线程的栈内存。

    ps: 中间截图截一半时,电脑突然花屏 重启,幸好没啥事。

    (Ashiamd的github个人学习笔记)[https://ashiamd.github.io/docsify-notes/#/README] ~小尾巴~
  • 相关阅读:
    在SAP云平台上部署和运行Docker应用
    SAP ABAP maintanence view的数据校验机制
    SAP CRM user参数CRM_UI_PROFILE是在哪行ABAP代码里读取的
    sublime text的dockerfile语法高亮插件
    SAP Business Application Studio和SAP云平台Destination
    SAP UI5应用访问OData metadata的url和Destination
    SAP CRM note的自动拷贝
    合并二维数组
    redis命令手册
    redis性能测试工具的使用
  • 原文地址:https://www.cnblogs.com/Ashiamd/p/14054498.html
Copyright © 2011-2022 走看看