对于运行时数据区域被划分为5个区域,方法区(Method Area) ,虚拟机栈(VM Stack), 本地方法栈(Native Method Stack), 堆(Heap),程序计数器(Program Counter Register)
方法区 和 堆 由所有线程共享,其他是线程隔离的。
当前线程所执行的字节码的行号指示器
虚拟机栈描述的是Java方法执行的线程内存模型
|(Native Method Stacks)与虚拟机栈所发挥的作用类似,只是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务。
方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
运行时常量池(Runtime Constant Pool)是方法区的一部分
graph TD
1[new] --> 2{指令参数能否<br>在常量池中定位到<br>一个类的符号引用}
2 -->|能| 3{检查是否已经被<br>加载解析和初始化}
2 -->|不能| 4[加载过程]
3 -->|已完成| 5[分配内存]
3 -->|未完成| 4
4 --> 5
5 --> 6[初始化零值]
6 --> 7[设置对象信息如对象头等]
7 --> 8(加载完成)
8 --> 9[init]
对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)
对象真正存储的有效信息,即我们在程序代码里面所定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的字段都必须记录起来
不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用
HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是任何对象的大小都必须是8字节的整数倍。对象头部分已经被精心设计成正好是8字节的倍数(1倍或者2倍),因此,如果对象实例数据部分没有对齐的话,就需要通过对齐填充来补全
Java程序会通过栈上的reference数据来操作堆上的具体对象
堆溢出:
简要检查步骤:
溢出原因(常量池):
溢出原因(方法区)
异常场景:
JDK 8以后,永久代便完全退出了历史舞台,元空间作为其替代者登场。在默认设置下,前面列举的那些正常的动态创建新类型的测试用例已经很难再迫使虚拟机产生方法区的溢出异常了
-XX:MaxMetaspaceSize:设置元空间最大值,默认是-1,即不限制,或者说只受限于本地内存大小。·
-XX:MetaspaceSize:指定元空间的初始空间大小,以字节为单位,达到该值就会触发垃圾收集进行类型卸载,同时收集器会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过-XX:MaxMetaspaceSize(如果设置了的话)的情况下,适当提高该值。
-XX:MinMetaspaceFreeRatio:作用是**在垃圾收集之后控制最小的元空间剩余容量的百分比,**可减少因为元空间不足导致的垃圾收集的频率。类似的还有-XX:Max-MetaspaceFreeRatio,用于控制最大的元空间剩余容量的百分比。
直接内存(Direct Memory)的容量大小可通过-XX:MaxDirectMemorySize参数来指定,如果不去指定,则默认与Java堆最大值(由-Xmx指定)一致
哪些内存需要回收?
什么时候回收?
如何回收?
在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;
优势
问题(为什么 java 没有使用引用计数器)
javaTestGc objA = new TestGc();
TestGc objB = new TestGc();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
System.gc();
这个算法的基本思路就是通过一系列称为**“GC Roots”的根对象作为起始节点集**,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为**“引用链”(Reference Chain),如果某个对象到GC Roots间没有任何引用链相连**,或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的。
根据用户所选用的垃圾收集器以及当前回收的内存区域不同,还可以有其他对象“临时性”地加入,共同构成完整GC Roots集合。
java 中引用的传统定义导致引用只有“被引用”或者“未被引用”两种状态,JDK 1.2版之后,Java对引用的概念进行了扩充,将引用分为**强引用(StronglyRe-ference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)**4种,
即使在可达性分析算法中判定为不可达的对象,也不是“非死不可”的
graph TD
1[可达性分析] --> 2{是否有引用链}
2 -->|有|3(end)
2 -->|没有|4{是否要执行<br>finalize方法}
4 --> |没有覆盖finalize方法<br>已经被调用过<br>没必要执行finalize|5(回收对象)
4 --> |有必要执行finalize方法|6[对象置入F-Queue的队列]
6 --> 7(*)
7 --> 8[在Finalizer中重新建立引用<br>使GC可达<br>避免被回收]
t1(*) --> t2[由虚拟机自动建立的<br>低调度优先级的<br>Finalizer线程]
t2 --> t3[执行F-Queue中<br>对象的Finalizer方法]
t3 --> t4[不承诺一定会等待它运行结束]
t4 --> t5(end)
在finalizer()中重新被引用,可能(finalizer()不一定被执行)可以避免被回收,前提得在二次标记之前执行 finalizer(),所以对象在执行了 finalizer() 之后不一定被回收
而任何一个对象的 finalize() 方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法不会被再次执行
finalize()的运行代价高昂,不确定性大,无法保证各个对象的调用顺序,如今已被官方明确声明为不推荐使用的语法。
建议完全可以忘掉Java语言里面finalize()的这个方法
主要回收两部分内容:废弃的常量和不再使用的类型
细节方面,可以阅读RichardJones撰写的《垃圾回收算法手册》的第2~4章的相关内容
垃圾收集算法可以划分为**“引用计数式垃圾收集”(Reference Counting GC)和“追踪式垃圾收集”**(Tracing GC)两大类,这两类也常被称作“直接垃圾收集”和“间接垃圾收集”。
两个分代假说
隐含的假说: 跨代引用假说(Intergenerational Reference Hypothesis):跨代引用相对于同代引用来说仅占极少数。
收集概念
最早出现也是最基础的垃圾收集算法
算法分为“标记”和“清除”两个阶段:
也可以反过来,标记存活的对象,统一回收所有未被标记的对象。
标记过程就是对象是否属于垃圾的判定过程
缺点
内存分为两块大小一样的区域,用以标记出需要回收对象后,把不用被回收的对象负责到半区中,然后清除原来半区的数据。
优点是清除效率提高了,也不存在空间碎片化问题
缺点是空间利用率变低,只有原来的一般
Java虚拟机大多都优先采用了这种收集算法去回收新生代
Appel式回收的具体做法是把新生代分为一块较大的Eden空间和两块较小的Survivor空间,每次分配内存只使用Eden和其中一块Survivor。发生垃圾搜集时,将Eden和Survivor中仍然存活的对象一次性复制到另外一块Survivor空间上,然后直接清理掉Eden和已用过的那块Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8∶1,也即每次新生代中可用内存空间为整个新生代容量的90%(Eden的80%加上一个Survivor的10%),只有一个Survivor空间,即10%的新生代是会被“浪费”的。当然,90%的对象可被回收仅仅是“普通场景”下测得的数据,任何人都没有办法百分百保证每次回收都只有不多于10%的对象存活,因此Appel式回收还有一个充当罕见情况的“逃生门”的安全设计,当Survivor空间不足以容纳一次Minor GC之后存活的对象时,就需要依赖其他内存区域(实际上大多就是老年代)进行分配担保(Handle Promotion)。
新生代分为一块较大的 Eden 空间 和两块较小的 Survivor 空间 (HotSpot虚拟机默认Eden和Survivor的大小比例是8∶1)
每次分配内存只使用Eden和其中一块Survivor
发生垃圾搜集时,将Eden和Survivor中仍然存活的对象一次性复制到另外一块Survivor空间上,然后直接清理掉Eden和已用过的那块Survivor空间
当Survivor空间不足以容纳一次Minor GC之后存活的对象时,就需要依赖其他内存区域(实际上大多就是老年代)进行分配担保(Handle Promotion)
默认以8:1来分配新生代空间,会得到 80%的 Eden 一个,10%的 Survivor 两个,其中 Eden 和一个 Survivor 充当新生代的作用,而剩下的 Surivivor 充当复制区,当存活的对象在复制区中放置不下时,一般会被放到老年代中
其中的标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存
移动则内存回收时会更复杂,不移动则内存分配时会更复杂。
从垃圾收集的停顿时间来看,不移动对象停顿时间会更短,甚至可以不需要停顿,但是从整个程序的吞吐量来看,移动对象会更划算。
HotSpot虚拟机里面关注吞吐量的Parallel Scavenge收集器是基于标记-整理算法的,而关注延迟的CMS收集器则是基于标记-清除算法的,这也从侧面印证这点
粗劣记录
根节点枚举
安全点(Safepoint)
抢先式中断(Preemptive Suspension):首先把所有用户线程全部中断,如果发现有用户线程中断的地方不在安全点上,就恢复这条线程执行,让它一会再重新中断,直到跑到安全点上。现在几乎没有虚拟机实现采用抢先式中断来暂停线程响应GC事件
主动式中断(Voluntary Suspension):设置一个标志位,各个线程执行过程时会不停地主动去轮询这个标志,一旦发现中断标志为真时就自己在最近的安全点上主动中断挂起
HotSpot使用内存保护陷阱的方式,虚拟机把某一位的内存页设置为不可读,那线程执行到对应指令时就会产生一个自陷异常信号,然后在预先注册的异常处理器中挂起线程实现等待
安全区域
记忆集与卡表(Remembered Set)
写屏障(Write Barrier)
卡表元素如何维护的问题?
HotSpot虚拟机里是通过写屏障技术维护卡表状态的
赋值前的部分的写屏障叫作写前屏障(Pre-WriteBarrier),在赋值后的则叫作写后屏障(Post-Write Barrier)
卡表在高并发场景下还面临着“伪共享”(False Sharing)问题
JDK 7之后,HotSpot虚拟机增加了一个新的参数-XX:+UseCondCardMark,用来决定是否开启卡表更新的条件判断
并发的可达性分析
三色标记
以下两个条件同时满足时,原本应该是黑色的对象被误标为白色:
Serial收集器是最基础、历史最悠久的收集器,曾经(在JDK 1.3.1之前)是HotSpot虚拟机新生代收集器的唯一选择。
特点:
ParNew收集器实质上是Serial收集器的多线程并行版本
除了Serial收集器外,目前只有它能与CMS收集器配合工作。
随着垃圾收集器技术的不断改进,更先进的G1收集器带着CMS继承者和替代者的光环登场。G1是一个面向全堆的收集器,不再需要其他新生代收集器的配合工作。所以自JDK 9开始,ParNew加CMS收集器的组合就不再是官方推荐的服务端模式下的收集器解决方案了。官方希望它能完全被G1所取代,甚至还取消了ParNew加SerialOld以及Serial加CMS这两组收集器组合的支持(其实原本也很少人这样使用),并直接取消了-XX:+UseParNewGC参数,这意味着ParNew和CMS从此只能互相搭配使用,再也没有其他收集器能够和它们配合了。读者也可以理解为从此以后,ParNew合并入CMS,成为它专门处理新生代的组成部分。ParNew可以说是HotSpot虚拟机中第一款退出历史舞台的垃圾收集器
与其他收集器不同 Parallel Scavenge 收集器的目标则是达到一个可控制的吞吐量(Throughput)。
所谓吞吐量就是处理器用于运行用户代码的时间与处理器总消耗时间的比值
高吞吐量
Parallel Scavenge 收集器提供了两个参数用于精确控制吞吐量
-XX:MaxGCPauseMillis : 最大垃圾收集停顿时间
-XX:GCTimeRatio:设置吞吐量大小
值是一个大于0小于100的整数,默认值为 99
这是垃圾收集时间占总时间的比率,相当于1 - 吞吐量
from: https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gc-ergonomics.html
-XX:GCTimeRatio=
nnnA hint to the virtual machine that it's desirable that not more than 1 / (1 + nnn) of the application execution time be spent in the collector.
For example
-XX:GCTimeRatio=19
sets a goal of 5% of the total time for GC and throughput goal of 95%. That is, the application should get 19 times as much time as the collector.By default the value is 99, meaning the application should get at least 99 times as much time as the collector. That is, the collector should run for not more than 1% of the total time. This was selected as a good choice for server applications. A value that is too high will cause the size of the heap to grow to its maximum.
由于与吞吐量关系密切,Parallel Scavenge收集器也经常被称作**“吞吐量优先收集器”**
-XX:+UseAdaptiveSizePolicy
Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记-整理算法
Parallel Old是Parallel Scavenge收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实现。
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。基于标记-清除算法实现的
由于在整个过程中耗时最长的并发标记和并发清除阶段中,垃圾收集器线程都可以与用户线程一起工作,所以从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。
优点: 并发收集、低停顿
缺点:
CMS收集器对处理器资源非常敏感
由于CMS收集器无法处理**“浮动垃圾”(Floating Garbage)**,有可能出现“Con-current Mode Failure”失败进而导致另一次完全“Stop The World”的Full GC的产生。
“浮动垃圾”(Floating Garbage): 并发阶段产生的垃圾,在当次垃圾收集中无法被回收,只能下一次垃圾收集时再清理掉。这一部分垃圾就称为“浮动垃圾”。
CMS无法等到老年代完全被填满时收集,必须预留一部分空间供并发收集时的程序运作使用
在JDK 5的默认设置下,CMS收集器当老年代使用了68%的空间后就会被激活, 可以适当调高参数 -XX:CMSInitiatingOccu-pancyFraction的值来提高CMS的触发百分比
JDK 6时,CMS收集器的启动阈值就已经默认提升至92%
这又会更容易面临另一种风险:要是CMS运行期间预留的内存无法满足程序分配新对象的需要,就会出现一次“并发失败”(Concurrent ModeFailure),这时候虚拟机将不得不启动后备预案:冻结用户线程的执行,临时启用Serial Old收集器来重新进行老年代的垃圾收集,但这样停顿时间就很长了。所以参数 -XX:CMSInitiatingOccupancyFraction 设置得太高将会很容易导致大量的并发失败产生,性能反而降低,用户应在生产环境中根据实际应用情况来权衡设置。
CMS是一款基于“标记-清除”算法实现的收集器,这意味着收集结束时会有大量空间碎片产生
CMS收集器提供了一个**-XX:+UseCMS-CompactAtFullCollection**开关参数(默认是开启的,此参数从JDK 9开始废弃):用于在CMS收集器不得不进行Full GC时开启内存碎片的合并整理过程,由于这个内存整理必须移动存活对象,(在Shenandoah和ZGC出现前)是无法并发的。这样空间碎片问题是解决了,但停顿时间又会变长
另外一个参数 -XX:CMSFullGCsBefore-Compaction(此参数从JDK 9开始废弃),这个参数的作用是要求CMS收集器在执行过若干次(数量由参数值决定)不整理空间的Full GC之后,下一次进入FullGC前会先进行碎片整理(默认值为0,表示每次进入Full GC时都进行碎片整理)。
Garbage First(简称G1)收集器是垃圾收集器技术发展历史上的里程碑式的成果,它开创了收集器面向局部收集的设计思路和基于Region的内存布局形式。
在G1收集器出现之前的所有其他收集器,包括CMS在内,垃圾收集的目标范围要么是整个新生代(Minor GC),要么就是整个老年代(Major GC),再要么就是整个Java堆(Full GC)。而G1跳出了这个樊笼,它可以面向堆内存任何部分来组成回收集(Collection Set,一般简称CSet)进行回收,衡量标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大,这就是G1收集器的MixedGC模式。
G1不再坚持固定大小以及固定数量的分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。收集器能够对扮演不同角色的Region采用不同的策略去处理,这样无论是新创建的对象还是已经存活了一段时间、熬过多次收集的旧对象都能获取很好的收集效果。
垃圾收集器的三项最重要的指标是:内存占用(Footprint)、吞吐量(Throughput)和延迟(Latency)
大多数情况下,对象在新生代Eden
区中分配。当 Eden
区没有足够空间进行分配时,虚拟机将发起一次 Minor GC
-XX:+PrintGCDetails
发生垃圾收集行为时打印内存回收日志,并且在进程退出的时候输出当前的内存各区域分配情况大对象就是指需要大量连续内存空间的Java对象
写程序时,应注意避免大对象:
-XX:PretenureSizeThreshold
参数,指定大于该设置值的对象直接在老年代分配,这样做的目的就是避免在Eden区及两个Survivor区之间来回复制,产生大量的内存复制操作。
虚拟机给每个对象定义了一个对象年龄(Age
)计数器,存储在对象头中
Minor GC
后仍然存活,并且能被 Survivor
容纳的话,该对象会被移动到 Survivor
空间中,并且将其对象年龄设为1岁Minor GC
,年龄就增加1岁-XX:MaxTenuringThreshold
可以设置对象晋升老年代的年龄阈值HotSpot虚拟机并不是永远要求对象的年龄必须达到-XX:MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到-XX:MaxTenuringThreshold中要求的年龄。
在发生Minor GC之前,虚拟机必须先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那这一次Minor GC可以确保是安全的。如果不成立,则虚拟机会先查看-XX:HandlePromotionFailure参数的设置值是否允许担保失败(Handle Promotion Failure);如果允许,那会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,或者-XX:HandlePromotionFailure设置不允许冒险,那这时就要改为进行一次FullGC
JVM ProcessStatus Tool
可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main()函数所在的类)名称以及这些进程的本地虚拟机唯一ID(LVMID,LocalVirtual Machine Identifier)
对于本地虚拟机进程来说,LVMID与操作系统的进程ID(PID,Process Identifier)是一致的
jps还可以通过RMI协议查询开启了RMI服务的远程虚拟机进程状态,参数hostid为RMI注册表中注册的主机名。
参数选项
选项 | 作用 |
---|---|
-q | 只输出LVMID,省略主类的名称 |
-m | 输出虚拟机进程启动时传递给主类 main() 函数的参数 |
-l | 输出主类的全名,如果进程执行的是 JAR 包, 则输出 JAR 路径 |
-v | 输出虚拟机进程启动时的 JVM 参数 |
jstat(JVM Statistics Monitoring Tool)
是用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类加载、内存、垃圾收集、即时编译等运行时数据,在没有GUI图形界面、只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的常用工具。
格式:
jstat [ option vmid [interval[s|ms] [count]] ]
[ protocol:][//]lvmid[@hostname[
]/servername]
jstat -gc 2764 250 20
选项 | 作用 |
---|---|
-class | 监视类加载、卸载数量、总空间以及类装载所耗费的时间 |
-gc | 监视 java 状况,包括 Eden 区, 2个 Survivor 区、老年代、永久代等的容量, 已用空间,垃圾收集时间合计等信息 |
-gccapactiy | 监视内容与 -gc 基本相同,但输出的主要关注 java 堆各个区域使用到的最大。 最小空间 |
-gcutil | 监视内容与 -gc 基本相同,但输出主要关注已使用空间占总空间的百分比 |
-gccause | 与 -gcutil 功能一样,但是会额外输出导致上一次垃圾收集产生的原因 |
-gcnew | 监视新生代垃圾收集情况 |
-gcnewcapacity | 监视内容与 -gcnew 基本相同,但输出主要关注使用到的最大、最小空间 |
-gcold | 监视老年代垃圾收集情况 |
-gcoldcapacity | 监视内容与-gcold 基本相同,但输出主要关注使用到的最大、最小空间 |
-gcpermcapacity | 输出拥挤代使用到的最大、最小空间 |
-compiler | 输出即时编译器编译过的方法,耗时等信息 |
-printcompilation | 输出已经被即时编译的方法 |
命令示例
-gcutil
$ jstat -gcutil 107581 S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
69.46 0.00 61.76 66.77 95.57 93.59 9840 71.693 8 2.304 73.997
S0
: Survivor0 ,使用 69.46%S1
: Survivor1 ,使用 0%E
: Eden ,使用 61.76%O
: olde 老年代,使用 66.77%P
: 这里没有(jdk1.8),表示 Permanent 永久代M
: Metaspace ,原空间,使用 95.57%CCS
: Compressed class space,压缩类空间利用率为百分比YGC
: Young GC,表示发生 Minor GC 的次数,9840 次YGCT
: 表示发生 Minor GC 的总耗时,总耗时 71.693 秒FGC
: Full GC,表示发生 Full GC 的次数,8 次FGCT
: 表示发生 Full GC 的总耗时, 总耗时 2.304 秒GCT
: 垃圾回收总时间,总耗时 73.997 秒jinfo(Configuration Info for Java)的作用是实时查看和调整虚拟机各项参数
jinfo命令格式:
jinfo [option] <pid>
选项 | 作用 |
---|---|
-flag <name> | 打印 name 的 jvm 参数的值 |
-flag [+|-]<name> | 添加或者删除(使...有效|无效) name 属性 |
-flag <name>=<value> | 设置 name 属性的值为 value |
-flags | 答应 vm flags |
-sysprops | 打印 java system properties |
<no option> | 答应所有配置 |
使用示例
$ jinfo -flag MaxHeapSize 107581 -XX
=536870912$ jinfo -flags 107581 Attaching to process ID 107581, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.92-b14 Non-default VM flags: -XX
=4 -XX=268435456 -XX=536870912 -XX=178782208 -XX=524288 -XX=89128960 -XX=179306496 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC Command line: -Xms256m -Xmx512m -XX:+UseParallelGC -javaagent:/data/agent/skywalking-agent.jar -Dskywalking.agent.service_name=external-gateway-server -javaagent:/opt/bonree/apm/agent/java/6.2.11/bonree.jar -Dbonree.smartagent=true$ jinfo -sysprops 107581 Attaching to process ID 107581, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.92-b14 java.runtime.name = Java(TM) SE Runtime Environment logPath = /data/logs sun.rmi.transport.tcp.responseTimeout = 200000 ...
jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为heapdump或dump文件)
用途:
命令格式
jmap [ option ] vid
选项 | 作用 |
---|---|
-dump | 生成 java 堆转存快照,格式为: -dump: [live,] format=b, file=<filename> <\pid>, 其中 live 子参数说明是否只 dump 出存活的对象 |
-finalizerinfo | 显示在 F-Queue 中等待 Finalizer 线程执行 finalize 方法的对象。 只在 Linux/Solaris 平台下有效 |
-heap | 显示 java 堆详细信息,如使用哪种回收器、参数配置、分代状况等。 只在 Linux/Solaris 平台下有效 |
-histo | 显示堆中对象统计信息,包括类、实例数量、合计容量 |
-permstat | 以 ClassLoader 为统计口径显示永久代内存状态。 只在 Linux/Solaris 平台下有效 jdk1.8 已经删除这个操作(因为没有永久代) |
-F | 当虚拟机进程对 -dump 选项没有响应时,可使用这个选项强制生 成 dump 快照。 在 Linux/Solaris 平台下有效 |
-clstats | 打印类加载器统计信息 |
jhat(JVM Heap Analysis Tool)命令与jmap搭配使用,来分析jmap生成的堆转储快照。
jhat的分析功能相对来说比较简陋,一般不使用
jstack(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照(一般称为threaddump或者javacore文件)
命令格式
选项 | 作用 |
---|---|
-F | 单正常输出的请求不被响应时,强制输出线程堆栈 |
-l | 除堆栈外,显示关于锁的附加信息 |
-m | 如果调用到本地方法的话。可以显示 C/C++ 堆栈 |
。。。
工具 | 说明 |
---|---|
JConsole | 最古老的,在JDK 5时期就已经存在的虚拟机监控工具 JDK中的正式成员,跟随jdk一起发布 |
JHSDB | JHSDB虽然名义上是JDK 9中才正式提供 但之前已经以sa-jdi.jar包里面的HSDB(可视化工具) 和CLHSDB(命令行工具)的形式存在了很长一段时间 JDK中的正式成员,跟随jdk一起发布 |
VisualVM | JDK 6 Update 7中首次发布 现在成为一个独立发展的开源项目 不是JDK中的正式成员,需要下载 |
JMC (Java Mission Control) | BEA公司的图形化诊断工具 JDK 7 Update 40时开始随JDK一起发布 从JDK 11开始又被移除出JDK 在生产环境是需要付费的 |
JCMD、JHSDB和基础工具对比
基础工具 | JCMD | JHSDB |
---|---|---|
jps -lm | jcmd | N/A |
jamp -dump <pid> | jcmd <pid> GC heap_dump | jhsdb jmap --binaryheap |
jmap -histo <pid> | jcmd <pid> GC class_hsitogram | jhsdb jmap --histo |
jstack <pid> | jcmd <pid> Thread.print | jhsdb jstack --locks |
jinfo -sysprops <pid> | jcmd <pid> VM.system_properties | jhsdb info --sysprops |
jinfo -flags <pid> | jcmd <pid> VM.flags | jhsdb jinfo --flags |
命令行方式这里不提,以下主要介绍可视化
JHSDB是一款基于服务性代理(Serviceability Agent,SA)实现的进程外调试工具。
Heap Parameters: Gen 0: eden [0x0000000019c00000,0x0000000019c5a9f8,0x0000000019eb0000) space capacity = 2818048, 13.17195448764535 used from [0x0000000019f00000,0x0000000019f50000,0x0000000019f50000) space capacity = 327680, 100.0 used to [0x0000000019eb0000,0x0000000019eb0000,0x0000000019f00000) space capacity = 327680, 0.0 usedInvocations: 1 Gen 1: old [0x0000000019f50000,0x000000001a0724e8,0x000000001a600000) space capacity = 7012352, 16.95716358790888 usedInvocations: 0
本文作者:Yui_HTT
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!