关于jvm网络上有很多关于其介绍,本文主要从 Java为什么需要垃圾回收、Java对象创建过程、JVM数据结构、垃圾回收算法、垃圾对象如何被识别、垃圾回收器种类及使用场景、GC日志查看、JVM监控工具如何使用、JVM对象大小计算 等方面介绍JVM工作原理。
引用方式:Java采用垃圾回收,因为在java中所有对象变量都是引用,当一个引用被新对象覆盖掉时,就没有引用指向原来的对象了,这个对象就失去引用了,对java来说这就是垃圾变量需要被回收调。而C++仍然可以调用其析构函数(通过指向对象的变量),而java的引用已经指向其他对象。
创建方式:Java创建对象只需要new出一个对象,不会管对象的生命周期及内存释放,长时间大量的垃圾对象一定回占满内存,这两点决定Java需要垃圾回收的原因。
首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、验证、准备、解析、和初始化过。如果没有那就表明该类还没有被虚拟机加载无法创建,需要先执行类的加载过程。
JVM堆内存绝对规整的前提下,已使用的内存放在一边,空闲的在另一边,中间放着一个指针作为分界点的指示器,那所分配的内存仅仅就是把那个指针向空闲的那边挪动一段与对象大小相等的距离。此方法为顺序IO比随机IO性能高。
指针碰撞如果JVM堆内存并不是规整的,已使用的内存和未使用的内存混合在一起,那就没办法按照指针碰撞的方式为新生对象分配内存,JVM必须维护一个列表,记录哪些内存块是可用的,再分配的时候从列表中找到一块足够大的空间会分给对象实例,并更新列表记录,如果列表内存不足就触发GC回收JVM堆空间,这种分配方式成为“空闲列表”。此方法为随机IO比顺序IO性能差,但是更更有效的利用JVM内存空间。
空闲列表//Unsafe.allocateMemory 申请内存
public native long allocateMemory(long arg0);
//Unsafe.freeMemory 内存释放
public native void freeMemory(long arg0);
JVM中如何高效的查找对象,如何高效的做垃圾回收,JVM各个区域如何协调处理程序的调用逻辑,下面分析JVM的底层秘密JVM的数据结构。
后续更新
后续更新
后续更新
后续更新
JVM堆的数据结构
GC root tracing过程 JVM堆数据结构是图 具体构建类是OopMap.java,利用图的可到达算法实现,具体如何实现可到达及堆对象的快速定位 后续更新
JVM堆中对象数据结构
后续更新
收集器将Java堆划分出不同的区域,然后将回收对象依据其年龄(对象熬过垃圾回收收集过程的次数)分派到不同的区域中存储,一般将Java堆划分成新生代和老年代新生代,每次垃圾回收都会有大量的对象死去(IBM测量98%熬不过第一轮收集), 存活的对象逐步晋升到老年代中存放,有的虚拟机会将新生代划分成三个区域Eden:Survivor:Survivor = 8:1:1。
标记出所需要的回收对象,在标记完成后,统一回收掉所有被标记的对象,标记的过程就是随想是否属于垃圾的判定过程。
堆中包含大量的对象,而且大部分是被回收的,所以会进行大量标记和清除动作,执行效率会随对象数量的增长而降低。
标记清除之后会产生大量不连续的内存碎片,太多会导致等到需要分配较大对象无法找到足够连续的内存而提前触发垃圾回收。
标记清除算法将内存按容量划分成两块,每次只是用其中的一块,如果这块内存使用完了之后就将还存活的对象复制到另一块区域上去,然后再将已使用过的内存空间一次性清理掉会导致大量内存空间的开销,但是不用考虑内存空间碎片问题,往往采用这种方式回收新生代,设置两块更为合理的两块区域即 (Eden + Survivor) :Survivor = 9 : 1, 每次分配内存只会使用Eden和一块Survivor,垃圾收集后会将(Eden + Survivor)中任然存活的对象复制到另一个Survivor中,这样只有10%的空间是“浪费”的,之后这两个Survivor轮流当这个被“浪费”的空间,当然这个对应的垃圾收集器会使用额外的机制处理新生代对象存活超过10%的情况。
标记复制算法标记之后不是直接对可回收对象进行清理,而是让所有的存活对象都向内存空间的一端移动,然后直接清理边界以外的内存 移动存活对象并更新引用必须暂停用户线程,这种现象被称为Stop The World。
标记整理算法算法名称 | 时间开销 | 空间浪费 | 内存碎片 | 是否移动对象 |
---|---|---|---|---|
标记-清除算法 | 中等 | 不存在 | 存在 | 不存在 |
标记-复制算法 | 最快 | 存在 | 不存在 | 存在 |
标记-整理算法 | 最慢 | 不存在 | 不存在 | 存在 |
当堆中存储对象时,在对象头处维护一个counter计数器,如果一个对象增加了一个引用与之相连,则将counter++。如果一个引用关系失效则counter–。如果一个对象的counter变为0,则说明该对象已经被废弃已经成为垃圾对象。
引用软弱虚问题
JDK1.2开始增加了多种引用方式:软引用、弱引用、虚引用,且在不同引用情况下程序应进行不同的操作。如果我们只采用一个引用计数法来计数无法准确的区分这么多种引用的情况。
引用死锁性能问题
如果一个对象A持有对象B,而对象B也持有一个对象A,那发生了类似操作系统中死锁的循环持有,这种情况下A与B的counter恒大于1,会使得GC永远无法回收这两个对象。在多线程环境下回收性能也是一个重要的考虑因素,目前主流回收器都不采用此方案。
以GC Roots 为根对象为起始点集,根据引用关系向下搜索,搜索过程走过的路径称为引用链,如果某个对象到GC Roots之间没有引用链相连,那这个对象就是可回收的垃圾,GC Roots利用图论中的可达性原理来判断,内存是否需要被回收。对象是否回收还有个因素,F-Queue队列中对象finalize是否执行,并且下次GC时可达性分析不再GC Roots的引用链上,此时对象真正被回收。
GC Roots根有几种,一个对象可以属于一种以上的根,根类型为
Class 由系统类加载器(system class loader)加载的对象,这些类是不能够被回收的,他们可以以静态字段的方式保存持有其它对象。我们需要注意的一点就是,通过用户自定义的类加载器加载的类,除非相应的java.lang.Class实例以其它的某种(或多种)方式成为roots,否则它们并不是roots。
Thread 活着的线程Stack Local - Java方法的local变量或参数
JNI Local JNI方法的local变量或参数
JNI Global 全局JNI引用
Monitor Used 用于同步的监控对象
命令 | 含义 |
---|---|
java -XX:+PrintFlagsInitial -version | 查询JVM初始默认值 |
java -XX:+PrintFlagsFinal | 查询JVM修改更新值 |
java -XX:+UnlockExperimentalVMOptions | 解锁实验参数 允许使用实验性参数,JVM中有些参数不能通过-XX直接复制需要先解锁,比如要使用某些参数的时候,可能不会生效,需要设置这个参数来解锁;一般使用在一些低版本jdk想使用高级参数或者可能高版本有的参数情况 |
java -XX:+UnlockDiagnosticVMOptions | 解锁诊断参数 |
java -XX:+PrintCommandLineFlags -version | 回收器查看 |
更多jdk1.8设置请参考 官网
属性 | 参数名称 | 参数含义 | 默认值 | 重要级别 | 调优 | 备注 |
公共 | -Xms | 初始堆大小 | 物理内存的1/64(<1GB) | 高 | 可优化 | |
-Xmx | 最大堆大小 | 物理内存的1/4(<1GB) | 高 | 可优化 | ||
-Xmn | 年轻代大小(1.4or lator) | 高 | 可优化 | 注意:此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。 整个堆大小=年轻代大小 + 年老代大小 + 持久代大小. 增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8 |
||
-XX:NewSize | 新生代初始化内存的大小,应该小于-Xms的值 | 高 | 可优化 | 实际控制新生代大小参数是此参数生效 | ||
-XX:MaxNewSize | 新生代初始化内存最大值,应该小于-Xms的值 | 高 | 可优化 | |||
-XX:PermSize | 设置持久代(perm gen)初始值 | 物理内存的1/64 | 高 | 可优化 | jdk1.8版本以前 | |
-XX:MaxPermSize | 设置持久代最大值 | 物理内存的1/4 | 高 | 可优化 | jdk1.8版本以前 | |
-XX:MetaspaceSize | 元空间大小 | 20.8M | 高 | 无需 | 元空间大小,元空间本质跟永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代最大的区别在于:元空间并不在虚拟机中,而是使用本机内存。 元空间大小仅受本地内存限制。【jdk1.8版本以后】 |
|
-XX:MaxMetaspaceSize | 无限大 | 高 | 无需 | jdk1.8版本及以后 | ||
-Xss | 每个线程的堆栈大小 | 高 | 可优化 | JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右 一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。 和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:"” -Xss is translated in a VM flag named ThreadStackSize” 一般设置这个值就可以了。【实践中如果程序启动阶段出现各种奇怪的错误,可以检查下此值】. 查询默认值: java -XX:+PrintFlagsFinal -version | grep ThreadStackSize |
||
-XX:+HeapDumpOnOutOfMemoryError | 表示当JVM发生OOM时 自动生成dump文件 | false | 中 | 可优化 | 在某些来不及抓dump的线上oom场景可以开启此参数 | |
-XX:HeapDumpPath=/logs | dump生成文件路径 | 中 | 可优化 | |||
-XX:ThreadStackSize | Thread Stack Size | 中 | 慎重 | (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.] 【待验证jvm线程数和此值关系 线程数量=(机器本身可用内存-JVM分配的堆内存)/Xss的值】 |
||
-XX:NewRatio | 年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代) | 不通jdk版本不一致jdk1.8 默认值2 | 高 | 慎重 | -XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5 Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。 |
|
-XX:SurvivorRatio | Eden区与Survivor区的大小比值 | 2:8 | 高 | 慎重 | 设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10 | |
-XX:LargePageSizeInBytes | 内存页的大小不可设置过大, 会影响Perm的大小 | 低 | 慎重 | |||
-XX:+UseFastAccessorMethods | 原始类型的快速优化 | 低 | 慎重 | |||
-XX:+DisableExplicitGC | 关闭System.gc() | false | 低 | 慎重 | ||
-XX:MaxTenuringThreshold | 垃圾最大年龄 | 15 | 中 | 慎重 | 如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概率 该参数只有在串行GC时才有效. |
|
-XX:+AggressiveOpts | 加快编译 | 低 | 慎重 | |||
-XX:+UseBiasedLocking | 锁机制的性能改善 | 低 | 慎重 | |||
-Xnoclassgc | 禁用垃圾回收 | 中 | 慎重 | |||
-XX:SoftRefLRUPolicyMSPerMB | 每兆堆空闲空间中SoftReference的存活时间 | 1s | 低 | 慎重 | softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap | |
-XX:PretenureSizeThreshold | 可以设分配到新生代对象的大小限制。任何比这个大的对象都不会尝试在新生代分配,将在老年代分配内存 |
0 任何对象都可以有机会分配到新生代 | 低 | 慎重 | 单位字节 新生代采用Parallel Scavenge GC时无效 另一种直接在旧生代分配的情况是大的数组对象,且数组中无外部引用对象. |
|
-XX:TLABWasteTargetPercent | TLAB[一个线程专用的内存分配区域]占eden区的百分比 | 1% | 低 | 慎重 | 不建议改动 | |
-XX:+CollectGen0First | FullGC时是否先YGC | false | 低 | 慎重 | ||
下面设置回收器 | ||||||
回收器开启 | -XX:+UseSerialGC | Serial+Serial Old串行回收器 | 串行回收器 [Mark Sweep Compact GC] | |||
-XX:+UseParNewGC | ParNew+Serial Old,在JDK1.8废弃 | |||||
-XX:+UseConcMarkSweepGC | ParNew+CMS+Serial Old | CMS回收器 [Concurrent Mark-Sweep GC] | ||||
-XX:+UseParallelGC | 虚拟机运行在Server模式下的默认值,Parallel Scavenge+Serial Old(PS Mark Sweep) | Parallel老版本回收器 [Parallel GC with 4 thread(s)] | ||||
-XX:+UseParallelOldGC | Parallel Scavenge+Parallel Old | Parallel新版本回收器 [Parallel GC with 4 thread(s)] | ||||
-XX:+UseG1GC | G1+G1 | G1回收器 [Garbage-First (G1) GC with 4 thread(s)] |
JDK8默认垃圾回收器: Parallel Scavenge+Parallel Old(关注吞吐量)
JDK11默认垃圾回收器:G1(关注及时性)
JDKx?默认垃圾回收器:CMS(平衡吞吐和及时性)
PS:G1,CMS及PARALLEL GC的比较
G1,CMS及PARALLEL GC的比较_yjh314的博客-CSDN博客_parallelgc 和cms
PS: 下面文章有别人对G1 vs Parallel Scavenge+Parallel Old 垃圾回收期性能测试G1和Parallel Scavenge & Parallel Old组合谁收集的更快一些_熊猫小白的博客-CSDN博客_g1和parallel
回收方式 | 回收器类型 | 作用域 | 涉及回收器 | 回收器类别 | 涉及算法 | 回收流程 | 回收器关注点 | 适用场景 |
---|---|---|---|---|---|---|---|---|
Unexpected GC [意外] |
Space Shock[空间震荡] 比如大对象导致内存不足 |
|||||||
Explicit GC[手工执行GC] 比如手工触发system.gc |
||||||||
Partial GC [部分] |
分代 | Minor GC【青年代】 |
Serial | 串行 | 标记-复制 | 幸存者Eden-Survivor | 响应速度 | 单核客户端嵌入式 |
ParNew | 并行 | 标记-复制 | 响应速度 | 多核服务端做cms配合 | ||||
Parallel Scavenge | 并行 | 标记-复制 | 吞吐量优先 | 吞吐量优先 | ||||
Major GC【老年代】 |
SerialOld | 并行 | 标记-整理 | 待更新 | 响应速度 | 单核服务端 or CMS后备 | ||
ParallelOld | 并行 | 标记-整理 | 标记-用户线程暂停-活对象移位-清理边界内存 | 吞吐量 | 吞吐量优先 | |||
CMS | 并发 |
标记-清除 | 初始标记[STW]-并行标记-重新标记[STW]-并发清除 | 响应时间 | 响应时间要求大于吞吐量 | |||
分区 | Region独立区域 |
G1 | 标记-整理 | 初始标记-根区扫描-并发标记-重新标记[STW]-清除回收[STW] | 响应时间 | 可替代CMS 无内存碎片 可预测停顿时间,可以设置回收时间做到预测 | ||
ZGC | ||||||||
Shenandoah | ||||||||
Full GC [全量] |
||||||||
吞吐量
吞吐量 = CPU在用户应用程序运行的时间 / (CPU在用户应用程序运行的时间 + CPU垃圾回收的时间)
暂停时间
JVM在垃圾回收的时候stop the word的时间
内存占用
垃圾回收过程中内存占用
待补充
CMS回收器调优及总结
Serial回收器调优及总结
Parallel回收器调优及总结
G1回收器调优及总结
ZGC回收器调优及总结
命令 | 作用 |
---|---|
-XX:+PrintClassHistogram | 按下Ctrl+Break后,打印类的信息 |
-XX:+PrintGC | 输出GC日志 |
-XX:+PrintGCDetails | 输出GC的详细日志 |
-XX:+PrintGCTimeStamps | 输出GC的时间戳(以基准时间的形式 |
-XX:+PrintGCDateStamps | 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800) |
-XX:+PrintHeapAtGC | 在进行GC的前后打印出堆的信息 |
-XX:+PrintGCApplicationConcurrentTime | 输出GC之间运行了多少时间 |
-XX:+PrintGCApplicationStoppedTime | GC造成应用暂停的时间 |
-XX:+PrintTLAB | 查看TLAB空间的使用情况 |
XX:+PrintTenuringDistribution | 查看每次minor GC后新的存活周期的阈值 |
-Xloggc:../logs/gc.log | 日志文件的输出路径 |
springboot启动 java -server -Xms2048M -Xmx2048M -Xmn512m -XX:+DisableExplicitGC --server.port=8080
catinlin.sh文件修改 在catinlin.sh文件头加入 JAVA_OPTS=" -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/logs/gc.$$.log"
eclipse VM arguments启动参数修改 -Xms500m -Xmx4048m -Xss1024m -XX:PermSize=64M -XX:MaxPermSize=2024m -XX:ReservedCodeCacheSize=48m -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:/logs/jvm.log
标准终端类 jps、jinfo、jstat、jstack、jmap
功能整合类 jcmd、vjtools、arthas、greys
功能:可以列出正在运行的虚拟机进程,并线上虚拟机执行的主类名称及其本地虚拟机唯一ID。
命令 | 功能描述 |
---|---|
jps -h | 查看支持的命令 usage |
jps -q | 输出jvm运行程序的pid |
jps -m | 输出启动类main函数的参数 |
jps -l | 输出主类名,如果进程执行的为jar,则输出jar路径或者启动类路径 |
jps -v | 输出具体进程启动时jvm参数 |
dingzhichaodeMacBook-Pro:~ dzc$ jps -h
illegal argument: -h
usage: jps [-help]
jps [-q] [-mlvV] []
Definitions:
: [:]
dingzhichaodeMacBook-Pro:~ dzc$ jps -q
26770
29353
13162
功能:jinfo(JVM Configuration info)这个命令作用是实时查看和调整虚拟机运行参数
命令 | 功能描述 |
---|---|
jinfo -h | 查看支持的命令 usage |
jinfo pid | 显示jvm系统属性 与 vm参数信息,如最大最小堆,默认堆,垃圾收集器参数等 |
jinfo -flags pid | 显示jvm vm参数信息 |
jinfo -sysprops pid | 显示jvm系统属性 |
jinfo -flag MaxHeapSize 26770 | 显示特定的vm参数信息 MaxHeapSize就是查询vm堆最大值 |
dingzhichaodeMacBook-Pro:~ dzc$ jinfo -h
Usage:
jinfo [option]
(to connect to running process)
jinfo [option]
(to connect to a core file)
jinfo [option] [server_id@]
(to connect to remote debug server)
where
功能:jstat(JVM statistics Monitoring)是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
命令 | 功能描述 |
---|---|
jstat | 查看支持的命令及格式 |
jstat -options | 查询jstat -options支持参数 |
jstat - | jstat 选择监控那个进程,在单位时间内做什么,做多少次 例如 jstat -gc 28270 1s 100 【每秒监控28270进程gc监控100次】 |
命令 | 功能描述 | 参数细节描述 | 指标反馈 |
---|---|---|---|
-class | 监视类装载、卸载数量、总空间以及类装载所耗费的时间 | Loaded 装载类数量 Bytes 大小 Unloaded 卸载类数量 Time 总消耗时间 |
衡量项目的规模大小 |
-compiler | 输出被JIT编译过的方法、耗时等信息 | Compiled 编译数量 Failed 编译失败数量 Invalid 无效数量 Time 编译耗时 FailedType 失败类型 FailedMethod 失败的方法 |
|
-gc | 监视Java堆,包括Eden区、两survivor区、老年代、永久代等的容量、已用空间、GC时间合计等 | S0C 第一个幸存区的大小 S1C 第二个幸存区的大小 S0U 第一个幸存区的使用大小 S1U 第二个幸存区的使用大小 EU 伊甸园区的使用大小 OU 老年代使用大小 MU 方法区使用大小 CCSU 压缩类空间使用大小 YGCT 年轻代垃圾回收消耗时间 FGCT 老年代垃圾回收消耗时间 |
关注幸存区、伊甸园、年轻代、老年代大小信息 |
-gccapacity | 与-gc基本相同,但关注点为Java堆各个区域使用到的最大、最小空间 | NGCMN 新生代最小容量 NGCMX 新生代最大容量 NGC 当前新生代容量 S0C 第一个幸存区大小 S1C 第二个幸存区的大小 EC 伊甸园区的大小 OGCMN 老年代最小容量 OGCMX 老年代最大容量 OGC 当前老年代大小 OC 当前老年代大小 MCMN 最小元数据容量 MCMX 最大元数据容量 MC 当前元数据空间大小 CCSMN 最小压缩类空间大小 CCSMX 最大压缩类空间大小 CCSC 当前压缩类空间大小 YGC 年轻代gc次数 FGC 老年代GC次数 |
|
-gccause | 与-gcutil功能相同,但会额外输出导致上一次GC产生的原因 | S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC | |
-gcmetacapacity | MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT GCT | ||
-gcnew | 监控新生代GC情况 | S0C 第一个幸存区大小 S1C 第二个幸存区的大小 S0U 第一个幸存区的使用大小 S1U 第二个幸存区的使用大小 TT 对象在新生代存活的次数 MTT 对象在新生代存活的最大次数 DSS 期望的幸存区大小 EC 伊甸园区的大小 EU 伊甸园区的使用大小 YGC 年轻代垃圾回收次数 YGCT 年轻代垃圾回收消耗时间 |
|
-gcnewcapacity | 与-gcnew基本相同,但关注最大,最小空间 | NGCMN 新生代最小容量 NGCMX 新生代最大容量 NGC 当前新生代容量 S0CMX 最大幸存1区大小 S0C 当前幸存1区大小 S1CMX 最大幸存2区大小 S1C 当前幸存2区大小 ECMX 最大伊甸园区大小 EC 当前伊甸园区大小 YGC 年轻代垃圾回收次数 FGC 老年代回收次数 |
|
-gcold | 监控老年代GC情况 | MC 方法区大小 MU 方法区使用大小 CCSC 压缩类空间大小 CCSU 压缩类空间使用大小 OC 老年代大小 OU 老年代使用大小 YGC 年轻代垃圾回收次数 FGC 老年代垃圾回收次数 FGCT 老年代垃圾回收消耗时间 GCT 垃圾回收消耗总时间 |
|
-gcoldcapacity | 与-gcold相似 监控老年代GC情况 | OGCMN 老年代最小容量 OGCMX 老年代最大容量 OGC 当前老年代大小 OC 老年代大小 YGC 年轻代垃圾回收次数 FGC 老年代垃圾回收次数 FGCT 老年代垃圾回收消耗时间 GCT 垃圾回收消耗总时间 |
|
-gcutil | 与-gc基本相同,但关注点为Java堆各个区域已使用空间占总空间的百分比 | S0 Heap上的Survivor space 0区已使用空间的百分比 S1 Heap上的Survivor space 1区已使用空间的百分比 E Heap上Eden space区已使用空间的百分比 O Heap上的Old space区已使用空间的百分比 P Perm space区已使用空间的百分比 YGC 从应用程序启动到采样时发生Yang GC 的次数 YGCT 从应用程序启动到采样时Yang GC所用的时间【单位秒】 FGC 从应用程序启动到采样时Full GC的次数 FGCT 从应用程序启动到采样时Full GC所用的时间 GCT 从应用程序启动到采样时用于垃圾回收的总时间【单位秒】 |
|
-printcompilation | 输出已经被JIT编译的方法 | Compiled 被执行的编译任务的数量 Size 方法字节码的字节数 Type 编译类型 Method 编译方法的类名和方法名。类名使用"/" 代替 "." 作为空间分隔符. 方法名是给出类的方法名. 格式是一致于HotSpot - XX:+PrintComplation 选项 |
功能:用于生成堆转储快照(一般称为heapdump或dump文件)
其他可生成 heapdump 的方式:使用参数-XX:+HeapDumpOnOutOfMemoryError使用参数-XX:+HeapDumpOnCtrlBreak然后使用 Ctrl+Break 生成;Linux系统使用kill -3生成
另外它还可以查询 finalize 执行队列、Java堆和永久代的详细信息。
命令 | 功能描述 |
---|---|
jmap | 查看支持的命令及格式 |
jmap -dump | 生成堆转储快照 案例:jmap -dump:live,format=b,file=dzc.hprof 55671 |
jmap -finalizerinfo | 打印待回收对象信息 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象 案例:jmap -finalizerinfo 55671 |
jmap -heap | 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况 案例:jmap -heap 55671 |
jmap -histo | 显示堆中对象的统计信息 案例:jmap -histo 18601 |
jmap -F | 当-dump没有响应时,强制生成dump快照 案例:jmap -F 18601 |
功能:jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。
命令 | 功能描述 |
---|---|
jstack -F |
当正常输出请求不被响应时,强制输出线程堆栈 当java进程处于hung状态此命令可以恢复进程 案例:jstack -F 18601 |
jstack -l | 除堆栈外,显示关于锁的附加信息 案例:jstack -l 18601 |
jstack -m | 如果调用到本地方法的话,可以显示C/C++的堆栈 案例:jstack -m 18601 |
简易 JConsole、JVisualvm、HA、GCHisto[GC日志分析]、GCViewe
进阶 MAT、JProfiler
MAT是一个优秀的基于Eclipse的内存分析工具,是一个快速、功能丰富的JAVA Heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。使用内存分析工具从众多的对象中进行分析,快速的计算出在内存中对象的占用大小,看看是谁 阻止了垃圾收集器的回收工作,并可以通过报表直观的查看到可能造成这种结果的对象。使用MAT可以查看对象在内存的分布情况,进而排查内存泄漏的原因、找出重复引用的类、JAR分析集合的使用分析类加载器等常见的JVM异常。
从上图可以看到它的大部分功能,在饼图上,你会发现转储的大小和数量的类,对象和类加载器。正确的下面,饼图给出了一个印象最大的对象转储。移动你的鼠标一片看到对象中的对象的细节检查在左边。下面的Action标签中:
Action
Reports【重要】
Step By Step
MAT右键含义解释
list object(此对象持有外部对象及被外部对象持有情况明细)
show objects by class(此对象类型为维度汇总其持有外部对象及被外部对象持有的情况【重要】)
merger shortest paths to GC Root(合并最短路径到root节点,此指标可以检查gc为什么没有回收对象,是谁持有对象,强软弱虚对象介绍)
Java Basice(统计对象引用、加载器、线程情况)
Java Collections(不清楚)
Leak Identification(绘制报表)
Immediate Dominators:从类层面查找和此类有关系的所有类【重要】
Show Retained Set:显示对象的堆大小
Search Queries... :快捷搜索
Calculate Minimum Retained Size:不清楚
Calculate Precise Retained Size :不清楚
Histogram列含义解释
你创建的对象真正占了多少内存?作为程序员基本每天都在new 对象,那么new处理的对象真正占用了多少内存呢?你new处理的对象会不会导致OOM呢?下面介绍如何查看我们程序中对象大小的方法。
/*依赖pom*/
org.openjdk.jol
jol-core
{version}
/**对象信息查看*/
public class Test {
public static void main(String[] args) {
Object obj = new Object();
//查看对象内部信息
System.out.println("查看对象内部信息: "+ClassLayout.parseInstance(obj).toPrintable());
//查看对象外部信息
System.out.println("查看对象外部信息: "+GraphLayout.parseInstance(obj).toPrintable());
//获取对象总大小
System.out.println("对象总大小size : " + GraphLayout.parseInstance(obj).totalSize());
}
}