.NET CLR之垃圾回收(GC)

这篇具有很好参考价值的文章主要介绍了.NET CLR之垃圾回收(GC)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

笔记首发于:lengyueling.cn

什么是CLR

  • 公共语言运行库 (common language runtime,CLR) 是托管代码执行核心中的引擎。

  • 运行库为托管代码提供各种服务,如跨语言集成、代码访问安全性、对象生存期管理、调试和分析支持。

  • 它是整个.NET框架的核心,它为.NET应用程序提供了一个托管的代码执行环境。

  • 它实际上是驻留在内存里的一段代理代码,负责应用程序在整个执行期间的代码管理工作。

  • 它的其中一个重要作用就是进行.NET平台下语言的垃圾回收

GC垃圾回收

什么是垃圾回收

  • Net程序可以找出某个时间点上哪些已分配的内存空间没有被程序使用,并自动释放它们。

  • 自动找出并释放不再使用的内存空间的机制,就称为垃圾回收机制(Garbage Collection,简称GC)。

  • .NET CLR使用分代收集算法+标记压缩算法来进行GC。

垃圾回收的对象

  • 对于堆中内存,通过识别它们是否被引用来确定哪些对象是垃圾,哪些对象仍要被使用,垃圾就是没有被任何变量、对象引用的内容。

  • GC只负责堆内存的垃圾回收,引用类型都是存在堆中的,所以他的分配和释放都需要垃圾回收机制来管理。

  • 栈上的内存是通过系统自动管理的,值类型在栈中分配内存,他们有自己的生命周期,不需要主动对他们进行管理,系统会自动分配和释放。

垃圾回收的主要作用

  • 分配对象(比如说实例化对象的时候负责分配内存给对象)

  • 垃圾回收(比如回收我们写C#代码时产生的垃圾)

分配对象

  • 分为大对象和小对象分配

    • 超过85000字节(83k)的为大对象,否则为小对象

    • 大对象会被存放在第二代内存中,目的是减少性能损耗,提高性能

  • 分配小对象在短暂堆或者由自由对象列表进行分配,分配大对象直接在大对象堆段中

    • 一个区域->多个堆(普通堆和短暂堆)

      • 区域是CLR初始化的时候内存里开辟的一段空间

    • 在CLR中分为3个代:0代(存放短暂堆,存放小对象),1代(存放短暂堆,存放小对象),2代(存放普通堆,同时存放大对象和小对象)

      • 代是GC机制中使用的一种算法(分代算法),每次分配都有可能GC以释放内存(某一代存不下时,或者后面说的各种触发GC的条件成立时)

    • 如果我们有一个堆可以放100个字节,一次GC分配后用了90个字节,剩余的字节就是自由对象,如果有多个堆形成的多个自由对象就是自由对象列表

垃圾回收

触发GC的条件

  • 分配对象找不到可用空间(代空间不足)

  • 分配量超过阈值(CLR初始化时的一个阈值上下限)

  • 收到Windows报告物理内存不足的通知

  • 直接调用GC.Collect()手动触发(unity可以在loading的时候触发)

  • CLR卸载AppDomain

  • CLR正在关闭

GC垃圾回收的步骤

.NET CLR之垃圾回收(GC)

  • 1.停止其他线程,切换其他线程到抢占模式

    • 合作模式:在CLR里面运行的线程,可以无限制的访问托管堆和非托管堆

    • 抢占模式:只能访问非托管堆,托管堆不能访问

    • 之所以有这步是因为gc的时候如果不进入抢占模式,可能会造成访问到被回收的对象而发生错误

  • 2.重新判定传入的GC回收目标的代是否合适,主要判断条件有:

    • 碎片空间率

    • 短暂堆剩余空间

    • 卡片扫描效率

    • 物理内存占用率

    • 是否执行后台GC

  • 3.判断是否执行后台GC

    • 执行后台GC,进行标记和清扫

    • 不执行后台GC,则执行普通GC,进行标记、计划、重定位、压缩、清扫等操作

  • 简略版本(标记压缩算法):

    • 如果0代内存满了,gc首先会认为堆中全是垃圾,然后进行下面两步

    • 标记对象:从根(静态对象、方法参数)开始检查被引用的对象,将其标记为可达对象,其他为不可达对象

    • 搬迁对象压缩堆,释放不可达对象,搬迁可达对象到1代,修改引用地址

    • 如果1代内存满了,重复上面步骤,将0代可达对象搬迁到1代,1代可达对象搬迁到2代堆,以此类推。

垃圾回收算法

标记清除(Mark Sweep)

  • 简单描述:

    • 是最基础的GC算法。

    • 分为标记阶段和清除阶段。

    • 标记阶段遍历堆(根的直接引用,然后递归)为所有的活动对象打上标记。

    • 清除阶段(从堆的开始到结束遍历每一个对象)如果是已经标记的,设置为未标记,未标记的连接到空闲链表(用作以后的分配),如果有连续的分块则合并。

  • 如何分配:遍历空闲链表根据策略选择合适的对象,下面是三种策略。

    • First - fit(遇到大于等于的分块就直接返回)

    • Best - fit(返回大于等于的最小分块)

    • Worst - fit(返回最大的分块)

  • 优点:

    • 简单

    • 与保守式GC 算法兼容(也就是不移动对象)

  • 缺点:

    • 碎片化(也就是空闲链表中存在,一堆不连续的小分块,不论采用那种分配策略都无法避免碎片化)

    • 分配速度慢(每次分配都需要遍历空闲链表,举个极端的,每次合适的都是最后一个)

    • 与写时复制技术不兼容(写时复制技术(众多UNIX 操作系统的虚拟存储中用到的高速化方法。)

    • 复制进程的时候大部分内存不会被复制而是共享,共享内存不能直接重写,想要重写得复制到自己的私有空间,不访问共享内存

.NET CLR之垃圾回收(GC)

引用计数(Reference Counting)

  • 简单描述:

    • 每个对象有个计数器,在每次指针更新时,新指向的对象的计数器++

    • 之前指向的对象的计数器--

    • 如果等于0回收,加入空闲链表。

  • 如何分配:遍历空闲链表

  • 优点:

    • 可即可回收垃圾(当计数器为0时直接回收)

    • 最大暂停时间短(每次指针更新时都会回收垃圾)

    • 没有必要沿指针查找(上面的标记清楚算法,需要由根开始查找)

  • 缺点:

    • 计数器值的增减处理繁重

    • 计数器要占用很多位

    • 实现繁琐复杂

    • 循环引用无法回收(比如根引用A ,A和B两个互相引用,当根不引用A的时候 A和B已经是垃圾了,但是互相引用计数器都是1,无法回收)

复制集合(Copy Collection)

  • 简单描述:

    • 把堆平分为From,To两个空间,如果现在活动对象,垃圾是在From空间,从根开始递归(深度遍历),把所有的对象复制到To空间,反之亦然。

    • 如何分配:当前活跃的空间,未分配的部分,按内存顺序分配。

  • 优点:

    • 优秀的吞吐量(能较短时间完成GC,和标记清楚算法比较,标记清楚需要遍历两次,而GC复制遍历一次+复制)

    • 可实现高速分配(直接在未分配的连续空间分配,不需要遍历啥的)

    • 不会发生碎片化(每次执行GC都把活动对象集中在开头,放在堆的一端的行为叫做压缩)

    • 与缓存兼容(深度遍历的复制,有引用关系的对象,在内存中放到了一起)

  • 缺点:

    • 堆使用效率低下(一分为二为两个空间,只有一半的堆能使用)

    • 不兼容保守式GC 算法

    • 递归调用函数(每次进行复制的时候都要调用函数,递归会消耗栈,所以还可能栈溢出)

.NET CLR之垃圾回收(GC)

标记压缩(整理)(Mark Compact)

  • 简单描述:

    • 是CLR使用的GC算法。

    • 结合标记清除算法和复制算法的优点并进行优化

    • 标记阶段遍历堆(根的直接引用,然后递归)为所有的活动对象打上标记

    • 整理阶段将存活对象移向内存的一段,然后清除边界外的对象

  • 优点:

    • 清除了标记-清除算法当中,内存区域碎片化的缺点。

    • 消除了复制算法当中,内存减半的高额代价。

  • 缺点

    • 从效率上来说,标记-整理算法要低于复制算法。

    • 移动对象的同时,如果对象被其它对象引用,则还需要调整引用 的地址。

    • 移动过程中,需要全程暂停用户应用程序,即STW。

.NET CLR之垃圾回收(GC)

分代收集(Generational Collection)

  • 当前商业虚拟机的垃圾收集都采用“分代收集”(Generational Collection)算法,这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分为几块。

  • 一般是把堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。

  • 在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。

  • 而老年代中因为对象存活率高、 没有额外空间对它进行分配担保,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。

资料参考、拓展阅读

Unity优化之GC分配问题_哔哩哔哩_bilibili(Unity优化之GC分配问题)

.Net CLR视频2021年最新讲解CLR核心机制,CLR模型,性能优化原理。_哔哩哔哩_bilibili(.Net CLR视频2021年最新讲解CLR核心机制,CLR模型,性能优化原理)

第9课:构造、析构、垃圾回收_哔哩哔哩_bilibili(【唐老狮】Unity系列之C#四部曲—C#核心-垃圾回收)

.NET:GC_丿灬鑫崽丶的博客-CSDN博客_.net core 析构函数(.NET:GC)

垃圾回收的算法与实现(一)三类基本算法_璃殇Yiyi的博客-CSDN博客(垃圾回收的算法与实现(一)三类基本算法)

CLR的GC_璃殇Yiyi的博客-CSDN博客(CLR的GC)

unity GC机制简单介绍_ZEKEGU1997的博客-CSDN博客_unity的gc(unity GC机制简单介绍)

Unity优化之GC——合理优化Unity的GC - zblade - 博客园(Unity优化之GC——合理优化Unity的GC)

C#——垃圾回收(GC)_面向大象编程的博客-CSDN博客_c# 垃圾回收(C#——垃圾回收(GC))

lua的GC原理_LJY_rookie的博客-CSDN博客(lua的GC原理)

.NET垃圾回收(GC)原理 - awp110 - 博客园(.NET垃圾回收(GC)原理)

四种垃圾回收算法(标记-清除算法【Mark-Sweep】,复制算法【Coping】,标记-整理算法【Mark-Compact】,分代收集算法【Generational Collection】) - ~晶晶~ - 博客园(四种垃圾回收算法)

标记整理算法(Mark-Compact)_永远的HelloWorld的博客-CSDN博客(标记整理算法(Mark-Compact))

http://t.csdn.cn/BOZ6m(标记-压缩(整理)算法)

浅析CLR的GC(垃圾回收器) - 3WLineCode - 博客园(浅析CLR的GC(垃圾回收器))

公共语言运行库_百度百科(公共语言运行库CLR)

托管代码和非托管代码_qq_38234381的博客-CSDN博客_托管代码和非托管代码(托管代码和非托管代码)文章来源地址https://www.toymoban.com/news/detail-514259.html

到了这里,关于.NET CLR之垃圾回收(GC)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java---垃圾回收算法(GC)

    目录 一、如何判断一个对象是否存活 1.引用计数法 2.可达性分析法 二、垃圾回收算法 1.标记清除法 2.复制算法 3.标记整理法 4.分代算法 具体流程 注意事项 空间分配担保原则 总结 Java 堆中存放着几乎所有的对象实例,垃圾回收器在对堆进行垃圾回收前,首先要判断这些对象

    2024年02月05日
    浏览(37)
  • JVM----GC(垃圾回收)详解

    Automatic Garbage Collection (自动垃圾回收)是JVM的一个特性,JVM会启动相关的线程,该线程会轮训检查heap memeory,并确定哪些是未被引用的(unreferenced),即未被使用的;哪些是被引用的(referenced),即正在使用的。 在C/C++语言中,对象内存的分配与回收,是手动进行分配与回收

    2024年02月09日
    浏览(45)
  • JVM:垃圾回收机制(GC)

    引用计数算法:         在对象中添加一个引用计数器,当每有一个地方引用它时,计数器值加一。当引用失效时,计数器值就减一。当一个对象的计数器为零时,表示该对象没有被任何其他对象引用,因此可以被释放。 优点 :是可以及时回收垃圾对象,避免内存泄漏,且

    2024年01月19日
    浏览(47)
  • 【Java】图解 JVM 垃圾回收(一):GC 判断策略、引用类型、垃圾回收算法

    垃圾 是指运行程序中 没有任何引用指向的对象 ,需要被回收。 内存溢出 :经过垃圾回收之后,内存仍旧无法存储新创建的对象,内存不够溢出。 内存泄漏 :又叫 “ 存储泄漏 ”,对象不会再被程序使用了,但是 GC 又不能回收它们。例如:IO 流不适用了但是没有被 Close、

    2024年02月19日
    浏览(48)
  • 【JVM】垃圾回收机制详解(GC)

    可以看jvm详解之后,再来理解这篇文章更好 堆和方法区,主要发生在堆中,然后主要发生在堆的伊甸园区(Eden)。 Java中的垃圾回收是根据 可达性分析算法(Reachability Analysis) 和 引用计数算法 来判断对象是否存活的。 JDK.1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:

    2024年02月13日
    浏览(53)
  • 02JVM_垃圾回收GC

    在 堆 里面存放着java的所有对象实例,当对象为“死去”,也就是不再使用的对象,就会进行垃圾回收GC 1.1引用计数器 介绍 在对象中添加一个引用计数器,当一个对象被其他变量引用时这个对象的引用计数器加1。当某个变量不再引用这个对象时引用计数器减1。当这个引用计

    2024年02月09日
    浏览(39)
  • 深入学习JVM —— GC垃圾回收机制

            前面荔枝已经梳理了有关JVM的体系结构和类加载机制,也详细地介绍了JVM在类加载时的双亲委派模型,而在这篇文章中荔枝将会比较详细地梳理有关JVM学习的另一大重点——GC垃圾回收机制的相关知识,重点了解的比如对象可达性的判断、四种回收算法、分代回收

    2024年02月14日
    浏览(46)
  • 【JAVAEE】JVM中垃圾回收机制 GC

      博主简介:想进大厂的打工人 博主主页: @xyk: 所属专栏: JavaEE初阶   上篇文章我们讲了java运行时内存的各个区域。 传送门:【JavaEE】JVM的组成及类加载过程_xyk:的博客-CSDN博客 对于程序计数器、虚拟机栈、本地方法栈这三部分区域而言,其生命周期与相关线程有关,随线

    2024年02月16日
    浏览(44)
  • 深入理解GO语言——GC垃圾回收二

    书接上回,无论怎么优化,Go V1.3都面临这个一个重要问题,就是mark-and-sweep 算法会暂停整个程序 。 Go是如何面对并这个问题的呢?接下来G V1.5版本 就用 三色并发标记法 来优化这个问题 Golang中的垃圾回收主要应用三色标记法,GC过程和其他用户goroutine可并发运行,但需要一

    2024年04月11日
    浏览(36)
  • 【JVM】JVM垃圾回收GC相关参数说明

    -XX:+PrintCommandLineFlags : 输出JVM启动参数 -XX:+UseSerialGC :在新生代和老年代使用串行收集器 -XX:SurvivorRatio :设置eden区大小和survivior区大小的比例 -XX:NewRatio :新生代和老年代的比 -XX:+UseParNewGC :在新生代使用并行收集器 -XX:+UseParallelGC :新生代使用并行回收收集器 -XX:+UseParallelO

    2024年02月04日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包