Skip to content

四火的唠叨

一个纯正程序员的啰嗦

Menu
  • 所有文章
  • About Me
  • 关于四火
  • 旅行映像
  • 独立游戏
  • 资源链接
Menu

常用的 JDK 自带命令行工具

Posted on 11/14/201306/23/2019 by 四火

heap

在这里可以找得到这些工具的列表,虽然官网上免责声明为 “The tools described in this section are unsupported and experimental in nature and should be used with that in mind. They might not be available in future JDK versions.”,但实际上这些工具还是非常有用的,尤其可以站在 JVM 的角度来定位问题。我在此简单罗列一些常用的工具和命令,以及相应的执行结果示例。如果你经常和 JVM 打交道,最好对这些工具的常用命令熟记。

 

jstat,这个工具很强大,可以监测 Java 虚拟机 GC 多方面的状态,具体参数含义参见此链接:

./jstat -gc 84012 1000 3

S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT
2112.0 2112.0  0.0    0.0   17024.0    0.0     63872.0     1319.9   21248.0 4728.1 743416  209.646   5      0.046  209.692
2112.0 2112.0  0.0    0.0   17024.0    0.0     63872.0     1319.9   21248.0 4728.1 743849  209.755   5      0.046  209.801
2112.0 2112.0  0.0    0.0   17024.0    0.0     63872.0     1319.9   21248.0 4728.1 744282  209.864   5      0.046  209.910

 

jmap,这大概是最常用的命令。下面这个命令不但可以列出类的实例数量,还有强制进行一次 full GC 的 “副作用”,这样的副作用对于定位某些问题很有帮助,参见 《使用堆外内存》:

./jmap -histo:live 84012

 num     #instances         #bytes  class name
----------------------------------------------
   1:           824        1177656  [B
   2:          8096        1106672
...

使用-heap 参数,则可以打印堆的使用情况:

./jmap -heap 84012

Attaching to process ID 84012, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.65-b04-462

using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 132120576 (126.0MB)
   NewSize          = 21757952 (20.75MB)
   MaxNewSize       = 174456832 (166.375MB)
   OldSize          = 65404928 (62.375MB)
   NewRatio         = 7
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 85983232 (82.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 19595264 (18.6875MB)
   used     = 16785688 (16.008079528808594MB)
   free     = 2809576 (2.6794204711914062MB)
   85.66196403375837% used
Eden Space:
   capacity = 17432576 (16.625MB)
   used     = 16785688 (16.008079528808594MB)
   free     = 646888 (0.6169204711914062MB)
   96.28920017328477% used
From Space:
   capacity = 2162688 (2.0625MB)
   used     = 0 (0.0MB)
   free     = 2162688 (2.0625MB)
   0.0% used
To Space:
   capacity = 2162688 (2.0625MB)
   used     = 0 (0.0MB)
   free     = 2162688 (2.0625MB)
   0.0% used
concurrent mark-sweep generation:
   capacity = 65404928 (62.375MB)
   used     = 1390576 (1.3261566162109375MB)
   free     = 64014352 (61.04884338378906MB)
   2.126102791520541% used
Perm Generation:
   capacity = 21757952 (20.75MB)
   used     = 4852336 (4.6275482177734375MB)
   free     = 16905616 (16.122451782226562MB)
   22.301437194088855% used

使用-permstat 参数,查看永久区:

./jmap -permstat 84012

Attaching to process ID 84012, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.65-b04-462
1239 intern Strings occupying 104312 bytes.
finding class loader instances ..Warning: skipping invalid TLAB for thread t@59779
Warning: skipping invalid TLAB for thread t@59527
Warning: skipping invalid TLAB for thread t@59907
Warning: skipping invalid TLAB for thread t@60163
Warning: skipping invalid TLAB for thread t@60419
Warning: skipping invalid TLAB for thread t@60675
Finding object size using Printezis bits and skipping over...
done.
computing per loader stat ..done.
please wait.. computing liveness...done.
class_loader	classes	bytes	parent_loader	alive?	type

	590	3973048	  null  	live
0x00000007f44cace0	0	0	  null  	live	sun/misc/Launcher$ExtClassLoader@0x00000007faff8a40
0x00000007f44c1478	8	143928	0x00000007f44cace0	live	sun/misc/Launcher$AppClassLoader@0x00000007fb056e88

total = 3	598	4116976	    N/A    	alive=3, dead=0	    N/A    

把内存中的堆 dump 成一个镜像文件:

./jmap -dump:live,format=b,file=/xxx/dump.core 84012

 

jstack,线程堆栈打印。注意 waiting to lock <xxx> 在等待锁,比如进入临界区时;locked <xxx> 表示当前同步操作,线程锁住了某资源;而 waiting on <xxx> 指的是在同步块内,wait 方法的执行中暂时地释放了该锁的占用,等唤醒的时候需要重新获取:

./jstack 84012

2013-11-11 18:30:35
Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.65-b04-462 mixed mode):

"Attach Listener" daemon prio=9 tid=7ff64e206800 nid=0x117782000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Low Memory Detector" daemon prio=5 tid=7ff64c80f000 nid=0x117c96000 runnable [00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" daemon prio=9 tid=7ff64c80e800 nid=0x117b93000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" daemon prio=9 tid=7ff64c80d800 nid=0x117a90000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=9 tid=7ff64c80d000 nid=0x11798d000 runnable [00000000]
   java.lang.Thread.State: RUNNABLE

"Surrogate Locker Thread (Concurrent GC)" daemon prio=5 tid=7ff64c80c000 nid=0x11788a000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=8 tid=7ff64e13d800 nid=0x11767f000 in Object.wait() [11767e000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <7f44c0ed0> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
	- locked <7f44c0ed0> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:171)

"Reference Handler" daemon prio=10 tid=7ff64e13c800 nid=0x11757c000 in Object.wait() [11757b000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <7f44c0018> (a java.lang.ref.Reference$Lock)
	at java.lang.Object.wait(Object.java:485)
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
	- locked <7f44c0018> (a java.lang.ref.Reference$Lock)

"main" prio=5 tid=7ff64c800800 nid=0x10f709000 runnable [10f708000]
   java.lang.Thread.State: RUNNABLE
	at test.Test.main(Test.java:7)

"VM Thread" prio=9 tid=7ff64e138000 nid=0x117479000 runnable

"Gang worker#0 (Parallel GC Threads)" prio=9 tid=7ff64e000000 nid=0x112b0f000 runnable

"Gang worker#1 (Parallel GC Threads)" prio=9 tid=7ff64e001000 nid=0x112c12000 runnable

"Gang worker#2 (Parallel GC Threads)" prio=9 tid=7ff64e001800 nid=0x112d15000 runnable

"Gang worker#3 (Parallel GC Threads)" prio=9 tid=7ff64e002000 nid=0x112e18000 runnable

"Gang worker#4 (Parallel GC Threads)" prio=9 tid=7ff64e002800 nid=0x112f1b000 runnable

"Gang worker#5 (Parallel GC Threads)" prio=9 tid=7ff64e003800 nid=0x11301e000 runnable

"Gang worker#6 (Parallel GC Threads)" prio=9 tid=7ff64e004000 nid=0x113121000 runnable

"Gang worker#7 (Parallel GC Threads)" prio=9 tid=7ff64e004800 nid=0x113224000 runnable

"Concurrent Mark-Sweep GC Thread" prio=9 tid=7ff64e0e2000 nid=0x1170f0000 runnable
"Gang worker#0 (Parallel CMS Threads)" prio=9 tid=7ff64e0e0800 nid=0x1166ea000 runnable

"Gang worker#1 (Parallel CMS Threads)" prio=9 tid=7ff64e0e1800 nid=0x1167ed000 runnable

"VM Periodic Task Thread" prio=10 tid=7ff64c820800 nid=0x117d99000 waiting on condition

"Exception Catcher Thread" prio=10 tid=7ff64c801800 nid=0x10f936000 runnable
JNI global references: 963

 

jinfo,可以打印 JVM 执行的参数信息,有一个非常大的作用在于,部分 JVM 参数在执行过程中是可以修改的,请参见这篇 《通过 jinfo 工具在 full GC 前后做 heap dump》,通过 jinfo 改变参数 HeapDumpBeforeFullGC 和 HeapDumpAfterFullGC,输出 heap dump 后,再改回来。

 

jhat,可以比对 core 文件之间的对象变化,支持对象查询语言(OQL),请参见这里。

./jhat -stack true -refs true -port 8080 -baseline /xxx/dump-baseline.core -debug 1 /xxx/dump-newer.core

 

javap,用于反编译 class 文件,对于 JVM 指令集,这里有完整的文档。

javap -c -v ./Test.class
Classfile xxx/Test.class
  Last modified Nov 11, 2013; size 441 bytes
  MD5 checksum 69488187cc8a8f166bc6dd0d517fb4cb
  Compiled from "Test.java"
public class test.Test
  SourceFile: "Test.java"
  minor version: 0
  major version: 50
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#16         //  java/lang/Object."":()V
   #2 = Integer            1048576
   #3 = Fieldref           #17.#18        //  java/lang/System.out:Ljava/io/PrintStream;
   #4 = Methodref          #19.#20        //  java/io/PrintStream.println:(Ljava/lang/Object;)V
   #5 = Class              #21            //  test/Test
   #6 = Class              #22            //  java/lang/Object
   #7 = Utf8
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               StackMapTable
  #14 = Utf8               SourceFile
  #15 = Utf8               Test.java
  #16 = NameAndType        #7:#8          //  "":()V
  #17 = Class              #23            //  java/lang/System
  #18 = NameAndType        #24:#25        //  out:Ljava/io/PrintStream;
  #19 = Class              #26            //  java/io/PrintStream
  #20 = NameAndType        #27:#28        //  println:(Ljava/lang/Object;)V
  #21 = Utf8               test/Test
  #22 = Utf8               java/lang/Object
  #23 = Utf8               java/lang/System
  #24 = Utf8               out
  #25 = Utf8               Ljava/io/PrintStream;
  #26 = Utf8               java/io/PrintStream
  #27 = Utf8               println
  #28 = Utf8               (Ljava/lang/Object;)V
{
  public test.Test();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: return
      LineNumberTable:
        line 4: 0

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: ldc           #2                  // int 1048576
         2: newarray       byte
         4: astore_1
         5: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
         8: aload_1
         9: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        12: goto          0
      LineNumberTable:
        line 7: 0
        line 8: 5
        line 9: 12
      StackMapTable: number_of_entries = 1
           frame_type = 0 /* same */

}

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

×Scan to share with WeChat

你可能也喜欢看:

  1. 看 JDK 源码,解几个疑问
  2. Issue record: “No thread for socket” about Memcached
  3. 同步、异步转化和任务执行
  4. JVM 致命错误日志(hs_err_pid.log)解读
  5. JVM 问题定位工具

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

订阅·联系

四火,啰嗦的程序员一枚,现居西雅图

Amazon Google Groovy Hadoop Haskell Java JavaScript LeetCode Oracle Spark 互联网 亚马逊 前端 华为 历史 同步 团队 图解笔记 基础设施 工作 工作流 工具 工程师 应用系统 异步 微博 思考 技术 数据库 曼联 测试 生活 眼界 程序员 管理 系统设计 缓存 编程范型 美股 英语 西雅图 设计 问题 面向对象 面试

分类

  • Algorithm and Data Structure (30)
  • Concurrency and Asynchronization (6)
  • System Architecture and Design (43)
  • Distributed System (18)
  • Tools Frameworks and Libs (13)
  • Storage and Data Access (8)
  • Front-end Development (33)
  • Programming Languages and Paradigms (55)
  • Testing and Quality Assurance (4)
  • Network and Communication (6)
  • Authentication and Authorization (6)
  • Automation and Operation Excellence (13)
  • Machine Learning and Artificial Intelligence (6)
  • Product Design (7)
  • Hiring and Interviews (14)
  • Project and Team Management (14)
  • Engineering Culture (17)
  • Critical Thinking (25)
  • Career Growth (57)
  • Life Experience and Thoughts (45)

推荐文章

  • 聊一聊分布式系统中的时间
  • 谈谈分布式锁
  • 常见分布式系统设计图解(汇总)
  • 系统设计中的快速估算技巧
  • 从链表存在环的问题说起
  • 技术面试中,什么样的问题才是好问题?
  • 从物理时钟到逻辑时钟
  • 近期面试观摩的一些思考
  • RSA 背后的算法
  • 谈谈 Ops(汇总 + 最终篇):工具和实践
  • 不要让业务牵着鼻子走
  • 倔强的程序员
  • 谈谈微信的信息流
  • 评审的艺术——谈谈现实中的代码评审
  • Blog 安全问题小记
  • 求第 K 个数的问题
  • 一些前端框架的比较(下)——Ember.js 和 React
  • 一些前端框架的比较(上)——GWT、AngularJS 和 Backbone.js
  • 工作流系统的设计
  • Spark 的性能调优
  • “残酷” 的事实
  • 七年工作,几个故事
  • 从 Java 和 JavaScript 来学习 Haskell 和 Groovy(汇总)
  • 一道随机数题目的求解
  • 层次
  • Dynamo 的实现技术和去中心化
  • 也谈谈全栈工程师
  • 多重继承的演变
  • 编程范型:工具的选择
  • GWT 初体验
  • java.util.concurrent 并发包诸类概览
  • 从 DCL 的对象安全发布谈起
  • 不同团队的困惑
  • 不适合 Hadoop 解决的问题
  • 留心那些潜在的系统设计问题
  • 再谈大楼扔鸡蛋的问题
  • 几种华丽无比的开发方式
  • 我眼中的工程师文化
  • 观点的碰撞
  • 谈谈盗版软件问题
  • 对几个软件开发传统观点的质疑和反驳
  • MVC 框架的映射和解耦
  • 编程的未来
  • DAO 的演进
  • 致那些自嘲码农的苦逼程序员
  • Java 多线程发展简史
  • 珍爱生命,远离微博
  • 网站性能优化的三重境界
  • OSCache 框架源码解析
  • “ 你不适合做程序员”
  • 画圆画方的故事

近期评论

  • Ticket: TRANSACTION 1.922915 BTC. Go to withdrawal >> https://yandex.com/poll/enter/BXidu5Ewa8hnAFoFznqSi9?hs=20bd550f65c6e03103876b28cabc4da6& on 倔强的程序员
  • panshenlian.com on 初涉 ML Workflow 系统:Kubeflow Pipelines、Flyte 和 Metaflow
  • panzhixiang on 关于近期求职的近况和思考
  • Anonymous on 闲聊投资:亲自体验和护城河
  • 四火 on 关于近期求职的近况和思考
  • YC on 关于近期求职的近况和思考
  • mafulong on 常见分布式基础设施系统设计图解(四):分布式工作流系统
  • 四火 on 常见分布式基础设施系统设计图解(八):分布式键值存储系统
  • Anonymous on 我裸辞了
  • https://umlcn.com on 资源链接
© 2025 四火的唠叨 | Powered by Minimalist Blog WordPress Theme