.NET GC工作流程
前言
在上文[如何获取GC的STW时间]一文中,我们聊到了如何通过监听GC发出的诊断事件来计算STW时间。里面只简单的介绍了几种GC事件和它的流程。
群里就有小伙伴在问,那么GC事件是什么时候产生的?分别是代表什么含义?
那么在本文就通过几个图为大家解答一下这个问题。
有哪些GC模式?
工作站和服务器模式
在.NET中,GC其实有一些不同的工作模式,根据客户端和服务器可以分为如下两种模式:
Workstation GC
Workstation GC(工作站GC),这种模式主要是为了满足基于UI的交互式应用程序设计的,交互式意味着GC的暂停时间要尽可能的短。因为我们不想因为触发GC导致较长的GC停顿。
- GC会更频繁的发生,每次暂停时间都会很短。
- 内存占用率更低,因为GC更频繁的发生,所以内存回收的更积极,占用率也会更低。
- 无论是否有配置多CPU核心,垃圾回收始终只使用一个CPU核心,只有一个托管堆。
- 内存段的大小设置会很小。
Server GC
Server GC (服务器GC),这种模式主要是为了满足基于请求处理的WEB等类型应用程序设计的,这意味着它更侧重于需要满足大的吞吐量,零星的停顿不会对齐产生重大的影响。
- GC的发生频率会降低,优先满足大吞吐量。
- 内存占用率会更高,因为GC发生的频率变低,内存中可能会有很多垃圾对象。
- 垃圾回收使用高优先级运行在多个专用线程上。每个CPU核心都提供执行垃圾回收的专用线程和堆,每个CPU核心上的堆都包含小对象、大对象堆。
- 因为多个垃圾回收线程一起工作,所以对于相同大小的堆,Server GC会回收的更快一些。
- 服务器垃圾回收通常会有更大的Segment,另外也会占用更多的资源。
并发与非并发模式
另外根据GC相对于用户线程的操作方式,还可以分为下面两种方式:
Non-Concurrent
Non-Concurrent(非并发GC),这种方式是一直存在于.NET中的,它适用于工作站和服务器模式,在GC进行过程中,所有的用户线程都会挂起。
Concurrent(已过时)
Concurrent (并发GC),并发GC模式它和用户线程同时工作,GC进行过程中只有少数几个过程需要挂起用户线程。所以它的实现也更加复杂,但是暂停时间会更短,性能也会更好,不过现在它已经过时,本文不会着重描述它。
Background
Background(后台GC),在.NET Framework 4.0以后,后台GC取代了并发GC,它只适用于Gen2的回收,但是它可以触发对于Gen0、Gen1的回收。根据WorkstationGC和ServerGC的模式会分别在一个或多个线程上执行。
GC工作流程
需要知道的GC事件
其实对于我们分析GC的工作来说,上文中提到的几个事件已经足够使用了,让我们再来回顾一下这些事件。
Microsoft-Windows-DotNETRuntime/GC/SuspendEEStart //开始暂停托管线程运行
Microsoft-Windows-DotNETRuntime/GC/SuspendEEStop //暂停托管线程完成
Microsoft-Windows-DotNETRuntime/GC/Start // GC开始回收
Microsoft-Windows-DotNETRuntime/GC/Stop // GC回收结束
Microsoft-Windows-DotNETRuntime/GC/RestartEEStart //恢复之前暂停的托管线程
Microsoft-Windows-DotNETRuntime/GC/RestartEEStop //恢复托管线程运行完成
图例
为了让大家能更清晰的看懂下面的图,会用不同形状和颜色的图像来代表不同的含义,如下方所示:

绿色:正在运行的用户线程。
红色:执行引擎进行线程冻结或线程恢复。
实线箭头:正在运行的GC线程。
虚线箭头:被暂停的线程。
黄色圆球:GC事件。
红色圆球:标记点。
WorkstationGC模式-非后台(并发)GC
下图是WorkStationGC(非后台)模式的执行流程,我们假设它是在一个双核的机器上运行(下文中都是假设在双核机器上运行),运行过程其实就像下图所示。

在上图中的事件流如下所示:
- GC/SuspendEEStart
- GC/SuspendEEStop
- GC/Start
- GC/Stop
- GC/RestartEEStart
- GC/RestartEEStop
其中各个标记点分别完成了如下工作:
- A->B:暂停所有用户线程
- B->C: 挑选一个用户线程作为GC线程,然后开始进行垃圾回收
- 选择-需要被回收的一代
- 标记-被回收的一代和更年轻一代对象
- 计划-GC决定是需要压缩整理堆还是只是清扫堆就够了
- 清扫、搬迁和压缩-根据上面计划的结果,执行清扫堆,或者搬迁活着的对象然后整理堆,最后所有对象的地址更新到新地址。
- C->D: GC工作结束,恢复线程运行
由于GC暂停了所有的线程,所以A->D就是此类GC的STW Time时间。
ServerGC模式-非后台(并发)GC
下图是ServerGC(非后台)模式的执行流程。

它与WorkstationGC模式的事件流和完成的工作都一致,唯一不同的就是它会根据当前的CPU逻辑核心数量创建单独的GC线程,比如上图就有2个GC线程。
另外在服务器GC模式中,用户线程还是可以作为GC线程来使用的,像用户线程1在GC发生的时候就做了一些GC工作。
WorkstationGC模式-后台GC
下图是WorkstationGC(后台)模式的执行流程,可以看到后台模式还是相当复杂的,会短暂的暂停多次,每一次都会执行不同的操作。

除了工作线程GC以外,另外会有单独的后台GC线程进行后台垃圾回收。
上图中的事件流如下所示:
- GC/SuspendEEStart
- GC/SuspendEEStop
- GC/Start
- GC/RestartEEStart
- GC/RestartEEStop
- GC/SuspendEEStart
- GC/SuspendEEStop
- GC/RestartEEStart
- GC/RestartEEStop
- GC/SuspendEEStart
- GC/SuspendEEStop
- GC/Start
- GC/Stop
- GC/RestartEEStart
- GC/RestartEEStop
- GC/Stop
其中各个标记点完成的工作如下所示:
- A->B:初始选择、标记
- 此时用户线程是暂停的
- 选择需要被回收的一代
- 找到GC roots,以便并发标记
- B->C:并发标记
- 此时用户线程是正常运行的
- 从上一步中找到的GC roots开始标记需要被回收的一代和年轻的代
- D->E:最终标记
- 此时用户线程是暂停的
- 扫描在并发标记过页面,看看是否有修改让对象重新活过来的
- F->G:清扫小对象堆
- 此时用户线程是正常运行的
- 清扫小对象堆的对象
- H->I:压缩整理小对象堆、清扫压缩整理大对象堆
- 此时用户线程是暂停的
- 选择了一个用户线程进行GC
- 用来压缩小对象堆的对象
- 另外也会压缩和整理大对象堆对象
- J->K:清扫大对象堆
- 此时用户线程是正常运行的
- 此时会清扫和整理大的对象堆
- 此时会禁止分配大对象,阻塞对应线程直到大对象堆回收完成
从上面的的流程中可以看到,后台GC主要是通过并发+多次短暂暂停来实现提升吞吐量和降低总体的STW Time的,其内部实现是非常复杂的,有兴趣的小伙伴可以直接看dotnet/runtime/gc.cpp文件。
ServerGC模式-非后台GC
下图是ServerGC(后台)模式的执行流程。

它与WorkstationGC模式的事件流和完成的工作都一致,唯一不同的就是它会根据当前的CPU逻辑核心数量创建单独的GC线程,比如上图就有2个GC线程,2个后台GC线程。
总结
今天带了解了一下.NET GC中的各个阶段和事件的顺序,当然这里只是简单的带大家了解一下,要知道在任何有runtime的平台中,GC是其中相当关键的东西,大家如果对GC感兴趣,可以阅读附录中的资料。
附录
- https://docs.microsoft.com/zh-cn/dotnet/standard/garbage-collection/
- https://github.com/dotnet/runtime/blob/main/src/coreclr/gc/gc.cpp
- https://netcoreimpl.github.io/
- http://www.tup.tsinghua.edu.cn/booksCenter/book_08454701.html
.NET GC工作流程的更多相关文章
- Mybatis第一篇【介绍、快速入门、工作流程】
什么是MyBatis MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为 ...
- [Inside HotSpot] C1编译器工作流程及中间表示
1. C1编译器线程 C1编译器(aka Client Compiler)的代码位于hotspot\share\c1.C1编译线程(C1 CompilerThread)会阻塞在任务队列,当发现队列有编 ...
- 优秀Java程序员必须了解的GC工作原理
一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,因为有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率 ,才能提高整个应 ...
- struts2工作流程
struts2的框架结构图 工作流程 1.客户端请求一个HttpServletRequest的请求,如在浏览器中输入http://localhost: 8080/bookcode/Reg.action ...
- SecondaryNameNode的工作流程
SecondaryNameNode是用来合并fsimage和edits文件来更新NameNode和metadata的. 其工作流程为: 1.secondary通知namenode切换edits文件 2 ...
- Storm 中什么是-acker,acker工作流程介绍
概述 我们知道storm一个很重要的特性是它能够保证你发出的每条消息都会被完整处理, 完整处理的意思是指: 一个tuple被完全处理的意思是: 这个tuple以及由这个tuple所导致的所有的tupl ...
- gitlab工作流程简介
gitlab工作流程简介 新建项目流程 创建/导入项目 可以选择导入github.bitbucket项目,也可以新建空白项目,还可以从SVN导入项目 建议选择private等级 初始化项目 1.本地克 ...
- Git 工作流程
Git 作为一个源码管理系统,不可避免涉及到多人协作. 协作必须有一个规范的工作流程,让大家有效地合作,使得项目井井有条地发展下去.”工作流程”在英语里,叫做”workflow”或者”flow”,原意 ...
- Spark基本工作流程及YARN cluster模式原理(读书笔记)
Spark基本工作流程及YARN cluster模式原理 转载请注明出处:http://www.cnblogs.com/BYRans/ Spark基本工作流程 相关术语解释 Spark应用程序相关的几 ...
随机推荐
- Mybaitis入门基础(一)MyBatis的概念引入及工作原理
阅读目录 一:对原生态JDBC问题的总结 二:MyBatis框架 三:mybatis入门程序 四:mybatis和Hibernate的本质区别与应用场景 五:小结 一:框架前言的那些事 良将难求 胜铁 ...
- JVM垃圾回收篇
点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. 基础概念 GC=jvm垃圾回收,垃圾回收机制是由垃圾回收器Garbage ...
- C# 一维数组如何快速实现数组元素的数据类型的转换?
一.场景假设 假设有一串字符串如下所示,字符串中的数字之间已用英文状态下的逗号隔开.要求用此字符串中的数字快速生成int类型的数组,且尽可能使用最少的代码量. string str = "1 ...
- 【已解决】Redis错误:Could not create server TCP listening socket 127.0.0.1:6379: bind: 操作成功完成。
报错:redis服务在window下启动,报错: Could not create server TCP listening socket 127.0.0.1:6379: bind: 操作成功完成. ...
- 1.9 初学者应选择哪个Linux发行版?
前面章节中,已经对几个常见的 Linux 发行版做了简单的介绍,那么对于初学者来说,选择哪个发行版的性价比更高呢? 通常情况下,初学者学习 Linux,是为了找一份和 Linux 相关的工作,那么问题 ...
- CSS躬行记(11)——管理后台响应式改造
为了提升业务人员操作管理后台的体验,花了点时间进行响应式的改造,紧急情况时,掏出手机就能工作. 利用CSS3的媒体查询,就能根据不同屏幕的尺寸采用不同的样式来渲染,目前使用的移动端屏幕阈值为750px ...
- css实现元素淡入淡出
@-webkit-keyframes fadeIn { 0% { opacity: 0; /*初始状态 透明度为0*/ } 50% { opacity: 0; /*中间状态 透明度为0*/ } 100 ...
- MySQL执行计划explain
一.简介 分析查询慢的原因,在查询语句前加explain即可.如: 二.输出格式 2.0 测试数据 # 表user_info CREATE TABLE `user_info` ( `id` bigin ...
- Sentinel介绍与使用 收藏起来
点赞再看,养成习惯,微信搜索[牧小农]关注我获取更多资讯,风里雨里,小农等你,很高兴能够成为你的朋友. 项目源码地址:公众号回复 sentinel,即可免费获取源码 前言 在家休息的的时候,突然小勇打 ...
- [持续更新] Python学习、使用过程中遇见的非代码层面知识(想不到更好的标题了 T_T)
写在前面: 这篇博文记录的不是python代码.数据结构.算法相关的内容,而是在学习.使用过程中遇见的一些没有技术含量,但有时很令人抓耳挠腮的小东西.比如:python内置库怎么看.python搜索模 ...