Java - JVM - jmap 简介

  1. 概述

    1. 继续聊 jvm 命令行工具
  2. 背景

    1. 之前聊过一些简单的命令行工具

      1. jps
        1. 查看当前 java 进程
      2. jinfo
        1. 查看 java 运行参数
        2. 查看当前 相关系统变量
      3. jstat
        1. 查看 jvm 的 堆内存,gc 统计信息
    2. 如果我想查看堆内存里到底有什么, 有办法吗?

      1. 当然有啦
        1. jmap 为当前的堆内存打快照
        2. jhat 解析快照, 并以 httpserver 的形式, 对外发布
    3. 作为一个学渣, 之前这些东西, 我都得过且过, 或者压根不管他们存在不存在

      1. 就算存在, 也不耽误我写 bug
      2. 其实应该鼓起勇气, 跟随好奇心, 去看书, 去找各路学霸交流
  3. 环境

    1. OS
      1. win10
    2. Java
      1. 1.8.0_201
    3. demo
      1. Spring Boot
        1. 2.1.3
    4. shell
      1. win10 cmd

1. 准备

  1. 示例进程

    1. 随便起了个 spring-boot 的 webmvc 工程
      1. 写个 hello world 之类的就行
  2. jps

    1. 获取进程的 pid
  3. 约定

    1. 后面只描述 本地执行 的结果
      1. jmap 其实可以远程执行, 这个有兴趣的同学自己去研究吧

2. jmap

  1. 概述

    1. jmap 简介
  2. jmap

    1. 展示工具
      1. 展示内容
        1. 堆内存
        2. 共享对象的内存映射
          1. 这块我目前不是很了解
      2. 展示方法

3. 命令使用

1. 共享对象映射

  1. 命令

    >jmap 8944
    Attaching to process ID 8944, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 25.181-b13
    0x000000005f8a0000      52K     C:\Program Files\Java\jdk1.8.0_181\jre\bin\management.dll
    0x000000005f8b0000      68K     C:\Program Files\Java\jdk1.8.0_181\jre\bin\nio.dll
    0x000000005f8d0000      104K    C:\Program Files\Java\jdk1.8.0_181\jre\bin\net.dll
    0x000000005f8f0000      140K    C:\Program Files\Java\jdk1.8.0_181\jre\bin\instrument.dll
    0x000000005f920000      88K     C:\Program Files\Java\jdk1.8.0_181\jre\bin\zip.dll
    0x000000005f940000      164K    C:\Program Files\Java\jdk1.8.0_181\jre\bin\java.dll
    0x000000005f970000      60K     C:\Program Files\Java\jdk1.8.0_181\jre\bin\verify.dll
    0x000000005f980000      8840K   C:\Program Files\Java\jdk1.8.0_181\jre\bin\server\jvm.dll
    0x0000000060230000      840K    C:\Program Files\Java\jdk1.8.0_181\jre\bin\msvcr100.dll
    ...
    
  2. 内容

    1. JVM version is 25.181-b13
      1. jvm 版本
    2. 0x000000005f8a0000
      1. 共享对象所映射的 内存地址
    3. 52K
      1. 共享对象的大小
    4. C:\Program Files\Java\jdk1.8.0_181\jre\bin\management.dll
      1. 共享对象在本地的路径
  3. 共享对象

    1. 疑问1

      1. 这玩意是干啥的, 之前听人讲 jvm 内存, 印象中没人提起过
        1. 可能是我之前没认真听讲吧...
    2. 又是一些疑问

      1. 启动 java 程序, 每次都要启动 jvm, 加载系统类
        1. 既然是这样的话, 有没有什么办法, 可以让这些老熟人能够区别于通用的类, 加载得更快
      2. 如果在一个环境下, 启动多个 jvm
        1. 如果每个 jvm 都把这些类加载一遍, 是不是又费时又费力
        2. 有没有办法, 把这个进程加快
    3. 共享对象

      1. 引入时间

        1. java 1.5
      2. 目的

        1. 加快特定类型的加载
          1. 特别是对 小型 java 应用, 效果拔群
        2. 并对这些特定类型, 提供 跨 jvm 共享
      3. 机制

        1. 文件机制
          1. linux
            1. classes.jsa 与 classeslist
              1. 将多个类放入 classes.jsa 中
              2. 将具体的类名, 记录在 classeslist 中
          2. win
            1. 老实说, 我还没找到具体的机制
            2. 但是从结果来看, 类型都放到了 dll 文件里
        2. 加载机制
          1. 这块暂时也没弄太明白
        3. 内存机制
          1. 这个我也暂时没弄明白
            1. 比如在 jvm 内存中的哪个位置
            2. 不过按理说, 应该会在 meta space 那块
            3. 而且通常, 这些 公用的类型, 应该也是 只读 的
      4. 其他

        1. 当然这个并不是重点, 看不懂也没关系

2. 堆内存概况

  1. 命令

    >jmap -heap 8944
    Attaching to process ID 8944, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 25.181-b13
    
    using thread-local object allocation.
    Parallel GC with 10 thread(s)
    
    Heap Configuration:
       MinHeapFreeRatio         = 0
       MaxHeapFreeRatio         = 100
       MaxHeapSize              = 17163091968 (16368.0MB)
       NewSize                  = 357564416 (341.0MB)
       MaxNewSize               = 5721030656 (5456.0MB)
       OldSize                  = 716177408 (683.0MB)
       NewRatio                 = 2
       SurvivorRatio            = 8
       MetaspaceSize            = 21807104 (20.796875MB)
       CompressedClassSpaceSize = 1073741824 (1024.0MB)
       MaxMetaspaceSize         = 17592186044415 MB
       G1HeapRegionSize         = 0 (0.0MB)
    
    Heap Usage:
    PS Young Generation
    Eden Space:
       capacity = 268435456 (256.0MB)
       used     = 26775152 (25.534774780273438MB)
       free     = 241660304 (230.46522521972656MB)
       9.974521398544312% used
    From Space:
       capacity = 44564480 (42.5MB)
       used     = 20312032 (19.371063232421875MB)
       free     = 24252448 (23.128936767578125MB)
       45.578972311580884% used
    To Space:
       capacity = 44564480 (42.5MB)
       used     = 0 (0.0MB)
       free     = 44564480 (42.5MB)
       0.0% used
    PS Old Generation
       capacity = 468189184 (446.5MB)
       used     = 15216480 (14.511566162109375MB)
       free     = 452972704 (431.9884338378906MB)
       3.2500708089830628% used
    
    16826 interned Strings occupying 2198488 bytes.
    
  2. 解释

    1. Parallel GC with 10 thread(s)

      1. 使用了 Parallel GC
      2. 使用了 10 个线程
    2. Heap Configuration

      1. 堆配置
        1. 具体配置我就不细说了
    3. Heap Usage

    4. 16826 interned Strings occupying 2198488 bytes.

      1. 有 16826 个内置字符串
      2. 占用了 2M 的空间
  3. 疑问

    1. NewRatio
      1. 完全不懂
    2. SurvivorRatio
      1. 完全不懂
    3. CompressedClassSpaceSize
      1. 它不是 meta space 的一部分吗, 怎么比 meta 还大
    4. internal Strings
      1. 这块老实说, 我也不是很懂...

3. 析构信息概述

  1. 命令

    >jmap -finalizerinfo 8944
    Attaching to process ID 8944, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 25.181-b13
    Number of objects pending for finalization: 0
    
  2. 解释

    1. Number of objects pending for finalization: 0
      1. 有 0 个对象, 即将被析构

4. 类型统计

  1. 命令

    >jmap -histo 8944
    
     num     #instances         #bytes  class name
    ----------------------------------------------
       1:        370446       47173928  [C
       2:         13190       16507488  [B
       3:        237789        5706936  java.lang.String
       4:          3867        3913304  [I
       5:         56074        2945096  [Ljava.lang.String;
       6:         42757        1368224  java.io.File
       7:         32465        1298600  java.util.LinkedHashMap$Entry
    
    ...
    ...
    
  2. 解释

    1. 排列顺序

      1. 默认是按照 bytes 的 降序 来做排列的
    2. 1: 370446 47173928 [C

      1. 1
        1. 编号为 1
      2. 370446
        1. 实例个数, 为 370446 个
      3. 47173928
        1. 实例占据内存空间, 为 47M
      4. [C
        1. 类型名为 [C
  3. 继续解释

    1. live
      1. -histo 还可以跟 live 参数
        1. -histo:live
        2. 结果会有比较大的差别
          1. live 只展现当前 存活 的对象
  4. 疑问

    1. [C
      1. 类型
        1. 有的类型, 不是直接显示的类型, 而是显示的这个...
        2. 我现在也是 蒙圈的, 后续再讲吧

5. 输出 dump 文件

  1. 命令

    # 1. 这次就带上 live 了
    # 2. 写作中途电脑又重启了, 所以 pid 换了
    >jmap -dump:live,format=b,file=dump.txt 14504
    Dumping heap to E:\dump.txt ...
    Heap dump file created
    
  2. 解释

    1. 选项
      1. -dump:live
        1. dump 当前 java 进程的堆内存
      2. format=b
        1. 使用 hprof 二进制格式
      3. file=dump.txt
        1. 指定输出文件名, 为 dump.txt
      4. 分割
        1. 使用 , 分割选项
  3. 结果

    1. 产生了一个 dump 文件
      1. 这个后续再讲吧...

ps

  1. ref

    1. 'Shared Object Memory' vs 'Heap Memory' - Java
      1. 引出了第二个 ref
    2. what is shared objects file?
      1. 引出了 第三个 ref
    3. Class Data Sharing
      1. 类型数据共享
        1. 官方文档
        2. 简单描述了下机制
        3. 感兴趣的童鞋, 可以自己了解, 这个和我关系不大, 我就不多说了
    4. jmap
      1. 官方文档
    5. Java-String.intern的深入研究
      1. internal Strings 的相关研究
        1. 有空的同学可以看一看
    6. jmap命令详解----查看JVM内存使用详情
      1. 博主讲得还不错
  2. 后续

    1. jhat
    2. 可视化工具
      1. 命令行工具讲完了, 就该讲用户喜闻乐见的可视化工具了
    3. jvm 内存的相关知识
    4. 之前那个 模糊的类型, 最好也了解一下
posted @ 2020-04-08 20:28  轩辕拾銉  阅读(370)  评论(0编辑  收藏  举报