JVM垃圾回收(二)- Minor GC vs Major GC vs Full GC
Minor GC vs Major GC vs Full GC
垃圾回收的活动会清理对内存中的不同区域,这些事件一般被称为Minor,Major以及Full GC events。本章我们会讨论这些清理事件的不同之处,当然,这些差别对我们来说并不是最重要的。
通常来说,对我们更有意义的是:应用是否满足了它的SLA,因为用户会监控应用的latency以及throughput。也只有在这个时候,GC events才与此有了关联。而对于GC事件来说,其中最重要的部分是:它们是否将应用 stop了,以及这个stop持续的时间。
Minor,Major以及Full GC这些术语早已被广泛使用,但是暂时对它们没有一个合适的定义,我们首先从对这三种GC events的介绍入手:
Minor GC
从Young space 做垃圾回收,称为Minor GC。这个定义确实比较清晰并且被广泛接受,但如果进一步对此做解释的话,有以下几点值得注意:
- 当JVM无法为一个新对象分配空间时(例如,Eden区域快满了),Minor GC一定会被触发。所以如果分配(allocation)操作越频繁,则Minor GC也会越频繁
- 在Minor GC 阶段,Tenured Generally会被忽略掉。从Tenured Generation到Young Generation的引用会被认定为GC roots。从Young Generation 到Tenured Generation的引用在mark 阶段会直接被忽略。
- 与普遍观点不同的一点是,Minor GC实际上会触发 stop-the-world pauses,暂停application的线程。对大部分应用来说,如果在Eden中,大部分对象被认为是垃圾,并且不会被复制到Survivor 或 Old 空间的话,应用暂停时间的长度基本可以忽略不计。反之,如果大部分年轻的对象并不会被回收,则Minor GC的暂停会花费更多的时间
Major GC vs Full GC
其实对这些属于其实没有一个官方的定义(无论是JVM中还是GC的研究论文中),不过基于我们刚刚介绍的Minor GC来看的话,对Major GC以及Full GC的定义可以简单的描述为:
- Major GC:清理Old空间
- Full GC:清理整个堆空间(包括Young 以及 Old 空间)
当然,里面具体的过程会更为复杂,而且大部分Major GC是由Minor GC 触发的,所以在很多情况下也不会将它们分开单独讨论。不过相对于辨别一个GC是Major GC还是Full GC,我们更应该关注的是:当前的GC事件是否暂时停掉了应用的线程,还是说可以与应用中的线程同时并发执行?
这个疑问甚至可以被内建于JVM标准工具上,对此,我们来看一个例子以做进一步解释。我们会使用两个不同的工具来跟踪一个运行了Concurrent Mark and Sweep collector(使用参数 -XX:+UseConcMarkSweepGC)的JVM,并比较它们的输出。
首先我们通过jstat的输出查看一下内部情况:
java -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC com.test.MyApplication

上面的片段是从一个运行了17s的JVM中获取的,我们可以看到12次Minor GC 后,发生了两次Full GC,持续大约一共50ms左右。你也可以通过基于GUI的工具如 jconsole 或 jvisualvm 查看这些输出。
然后我们看一下从同一个JVM里获取的GC输出日志。可以通过 -XX:+PrintGCDetails 开启GC日志:
java -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC com.test.MyApplication
日志内容可以提供更多相关信息:
3.157: [GC (Allocation Failure) 3.157: [ParNew: 272640K->34048K(306688K), 0.0844702 secs] 272640K->69574K(2063104K), 0.0845560 secs] [Times: user=0.23 sys=0.03, real=0.09 secs]
4.092: [GC (Allocation Failure) 4.092: [ParNew: 306688K->34048K(306688K), 0.1013723 secs] 342214K->136584K(2063104K), 0.1014307 secs] [Times: user=0.25 sys=0.05, real=0.10 secs]
... cut for brevity ...
11.292: [GC (Allocation Failure) 11.292: [ParNew: 306686K->34048K(306688K), 0.0857219 secs] 971599K->779148K(2063104K), 0.0857875 secs] [Times: user=0.26 sys=0.04, real=0.09 secs]
12.140: [GC (Allocation Failure) 12.140: [ParNew: 306688K->34046K(306688K), 0.0821774 secs] 1051788K->856120K(2063104K), 0.0822400 secs] [Times: user=0.25 sys=0.03, real=0.08 secs]
12.989: [GC (Allocation Failure) 12.989: [ParNew: 306686K->34048K(306688K), 0.1086667 secs] 1128760K->931412K(2063104K), 0.1087416 secs] [Times: user=0.24 sys=0.04, real=0.11 secs]
13.098: [GC (CMS Initial Mark) [1 CMS-initial-mark: 897364K(1756416K)] 936667K(2063104K), 0.0041705 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
13.102: [CMS-concurrent-mark-start]
13.341: [CMS-concurrent-mark: 0.238/0.238 secs] [Times: user=0.36 sys=0.01, real=0.24 secs]
13.341: [CMS-concurrent-preclean-start]
13.350: [CMS-concurrent-preclean: 0.009/0.009 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
13.350: [CMS-concurrent-abortable-preclean-start]
13.878: [GC (Allocation Failure) 13.878: [ParNew: 306688K->34047K(306688K), 0.0960456 secs] 1204052K->1010638K(2063104K), 0.0961542 secs] [Times: user=0.29 sys=0.04, real=0.09 secs]
14.366: [CMS-concurrent-abortable-preclean: 0.917/1.016 secs] [Times: user=2.22 sys=0.07, real=1.01 secs]
14.366: [GC (CMS Final Remark) [YG occupancy: 182593 K (306688 K)]14.366: [Rescan (parallel) , 0.0291598 secs]14.395: [weak refs processing, 0.0000232 secs]14.395: [class unloading, 0.0117661 secs]14.407: [scrub symbol table, 0.0015323 secs]14.409: [scrub string table, 0.0003221 secs][1 CMS-remark: 976591K(1756416K)] 1159184K(2063104K), 0.0462010 secs] [Times: user=0.14 sys=0.00, real=0.05 secs]
14.412: [CMS-concurrent-sweep-start]
14.633: [CMS-concurrent-sweep: 0.221/0.221 secs] [Times: user=0.37 sys=0.00, real=0.22 secs]
14.633: [CMS-concurrent-reset-start]
14.636: [CMS-concurrent-reset: 0.002/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
根据以上日志内容,我们可以看到在多次Minor GC后,一个与Minor GC不同的事件发生了。但是这里我们并没有看见两轮的Full GC 事件,而仅仅是一轮在Old 空间上发生的GC事件,由多个阶段组成:
- Initial Mark 阶段,耗时0.0041705,大约4ms。这个阶段是一个stop-the-world 事件,会暂时停止所有应用线程,以做初始的marking
- Markup and Preclean阶段与应用里的线程并行执行
- Final Remark 阶段,耗时0.00462010,大约46ms,这个阶段也是一个stop-the-world 事件
- Sweep 操作会被并行执行,不会停止应用的线程
所以从实际的垃圾回收日志来看,相对于之前jstat里查看到的两轮Full GC,其实真正发生的只有一次清理Old 空间的Major GC。
不过若单从jstat的输出来看,jstat其实已经将你引入了正确的(优化)决策方向,因为它完整的列出了两次stop-the-world事件(第一次4ms,第二次46ms),这两次事件对当时正在运行的线程产生了一共大约50ms的影响。并且jstat的输出已完全隐藏了并行任务的工作。
References:
https://plumbr.io/java-garbage-collection-handbook
JVM垃圾回收(二)- Minor GC vs Major GC vs Full GC的更多相关文章
- 二、JVM — 垃圾回收
JVM 垃圾回收 写在前面 本节常见面试题 本文导火索 1 揭开 JVM 内存分配与回收的神秘面纱 1.1 对象优先在 eden 区分配 1.2 大对象直接进入老年代 1.3 长期存活的对象将进入老年 ...
- .Net平台GC VS JVM垃圾回收
前言 不知道你平时是否关注程序内存使用情况,我是关注的比较少,正好借着优化本地一个程序的空对比了一下.Net平台垃圾回收和jvm垃圾回收,顺便用dotMemory看了程序运行后的内存快照,生成内存快照 ...
- Java:JVM垃圾回收(GC)机制
JVM垃圾回收算法 1.标记清除(Mark-Sweep) 原理: 从根集合节点进行扫描,标记出所有的存活对象,最后扫描整个内存空间并清除没有标记的对象(即死亡对象)适用场合: 存活对象较多的情况下比较 ...
- JVM垃圾回收机制GC
1. 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾.JVM的 ...
- JVM垃圾回收(GC)
JVM垃圾回收(GC) 1. 判断对象是否可以被回收 引用计数法:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收.此方法简单,但无法解决对象相互循环引用的问 ...
- JDK分析工具&JVM垃圾回收(转)
转自:http://blog.163.com/itjin45@126/blog/static/10510751320144201519454/ 官方手册:http://docs.oracle.com/ ...
- jvm - 垃圾回收
jvm - 垃圾回收 注意 : 本系列文章为学习系列,部分内容会取自相关书籍或者网络资源,在文章中间和末尾处会有标注 垃圾回收的意义 它使得java程序员不再时时刻刻的关注内存管理方面的工作. 垃圾回 ...
- Java虚拟机垃圾回收:内存分配与回收策略 方法区垃圾回收 以及 JVM垃圾回收的调优方法
在<Java对象在Java虚拟机中的创建过程>了解到对象创建的内存分配,在<Java内存区域 JVM运行时数据区>中了解到各数据区有些什么特点.以及相关参数的调整,在<J ...
- JVM内存管理、JVM垃圾回收机制、新生代、老年代以及永久代
内存模型 JVM运行时数据区由程序计数器.堆.虚拟机栈.本地方法栈.方法区部分组成,结构图如下所示. JVM内存结构由程序计数器.堆.栈.本地方法栈.方法区等部分组成,结构图如下所示: 1)程序计数器 ...
- 【搞定Jvm面试】 JVM 垃圾回收揭秘附常见面试题解析
JVM 垃圾回收 写在前面 本节常见面试题 问题答案在文中都有提到 如何判断对象是否死亡(两种方法). 简单的介绍一下强引用.软引用.弱引用.虚引用(虚引用与软引用和弱引用的区别.使用软引用能带来的好 ...
随机推荐
- Mybatis下的sql注入
以前只知道mybatis框架下,order by后面接的是列名是不能用#{},这样不起效果,只能用${},这样的话就可能产生sql注入.后来发现其实还有另外两种情况也是类似的: 1.order by ...
- H.264学习--1
1.宏块(Macro Block):一个编码图像首先要划分成多个块(4x4 像素)才能进行处理,显然宏块应该是整数个块组成,通常宏块大小为 ...
- Mac下安装SecureCRT并激活
今天花了好长的时间终于把SecureCRT安装成功了 现在分享给大家 安装的步骤, 希望对大家用帮助 Mac下的SecureCRT需要破解才能使用 所以有些费劲的.. 先下载SecureCRT和破解文 ...
- IP通信基础学习第七周(上)
局域网的优点:具有广播功能,从一个站点可以方便的访问全网,局域网上的主机可共享连接在局域网上的各种资源:便于系统的扩展和逐渐地演变,各设备的位置可灵活调整和改变:提高了系统的可靠性.可用性和生存性. ...
- JS所包含的大纲内容,以及JS中数据类型、运算符的介绍
JavaSctipt javascript:1.特效2.表单验证 原理:何时?1.找到标签 何时?2.操作标签 写在那里? 内联(行内)(不推荐直接写js代码,经常写方法调用) 写在标签里面,以属性的 ...
- 最大熵模型(MEM)
1. 最大熵原理 最大熵Max Entropy原理:学习概率模型时,在所有可能的概率模型(即概率分布)中,熵最大的模型是最好的模型. 通常还有其他已知条件来确定概率模型的集合,因此最大熵原理为:在满足 ...
- Vue 组件&组件之间的通信 之 非父子关系组件之间的通信
Vue中不同的组件,即使不存在父子关系也可以相互通信,我们称为非父子关系通信: 我们需要借助一个空Vue实例,在不同的组件中,使用相同的Vue实例来发送/监听事件,达到数据通信的目的: 实例: 初始加 ...
- linux查看与修改交换内存配置(解决zabbix-agent启动报错)
问题 zabbix-agent在一台centos6.5上启动报错: cannot allocate shared memory of size 949056: [28] No space left o ...
- 【题解】Luogu P2081 [NOI2012]迷失游乐园
原题传送门 这是当时冬令营课上讲的题,咕咕咕到了现在 如果这题没有环套树的话,就很套路了 需要两个数组up[i]和down[i],down[i]表示从i点第一步向下走的期望距离,up[i]表示从i点第 ...
- Exp4 恶意代码分析 20164303 景圣
Exp4 恶意代码分析 实验内容 实验点一:系统运行监控 (1)使用如计划任务,每隔一分钟记录自己的电脑有哪些程序在联网,连接的外部IP是哪里.运行一段时间并分析该文件,综述一下分析结果.目标就是找出 ...