【C# .Net GC】垃圾回收算法 应用程序线程运行时,
触发垃圾回收算法的条件
触发垃圾回收的条件
当满足以下条件之一时将发生垃圾回收:
操作系统报告低内存请看(将触发第2代垃圾回收)。 这是通过 OS 的内存不足通知或主机指示的内存不足检测出来。
由托管堆上已分配的对象使用的内存超出了可接受的阈值。 随着进程的运行,此阈值会不断地进行调整。触发第0代回收
调用 GC.Collect 方法。 几乎在所有情况下,你都不必调用此方法,因为垃圾回收器会持续运行。 此方法主要用于特殊情况和测试。如果应用程序代码通过调用 GC.Collect 方法并将
generation
参数指定为 2 来包含回收。- 应用程序调用new操作符创建对象,发现没有足够的地址空间来分配对象,CLR就经行垃圾回收。
- CLR卸载APPDomain,所有代0、1、2的垃圾回收。
- CLR正在关闭,收回内存
何时收集大型对象?
通常情况下,出现以下三种情形中的任一情况,都会执行 GC:
分配超出第 0 代或大型对象阈值。
阈值是某代的属性。 垃圾回收器在其中分配对象时,会为代设置阈值。 超出阈值后,会在该代上触发 GC。 因此,分配小型或大型对象时,需要分别使用第 0 代和 LOH 的阈值。 当垃圾回收器分配到第 1 代和第 2 代中时,将使用它们的阈值。 运行此程序时,会动态调整这些阈值。
这是典型情况,大部分 GC 执行都因为托管堆上的分配。
调用 GC.Collect 方法。
如果调用无参数 GC.Collect() 方法,或另一个重载作为参数传递到 GC.MaxGeneration,将会一起收集 LOH 和剩余的托管堆。
系统处于内存不足的状况。
垃圾回收器收到来自操作系统 的高内存通知时,会发生以上情况。 如果垃圾回收器认为执行第 2 代 GC 会有效率,它将触发第 2 代。
GC算法有哪些:
1、标记-清除算法
2、压缩算法
3、分代清除算法
标记-清除算法
标记不可达对象,然后将其清除。
标记对象的工作有两种模式:
- 同步 :标记工作开始之处,就暂停所有线程,开始标记工作。在CLR启动GC之前,除了触发垃圾回收的线程以外的所有托管线程均会挂起。目的是防止线程在clr检查期间访问对象并修改其状态。
- 并发 :起一个低优先级的线程执行标记工作,直到找到有为0的对象,再暂停所有线程,进行垃圾回收工作 在 .NET Core 中,服务器/工作站垃圾回收既可以是非并发也可以是后台执行。
垃圾回收算法
初始化GC,初始化CLR 的同时也初始化了GC。
1、CLR启动时会选择一个GC模式,进程终止前该模式不会改变。
2、加载 CLR 时,GC 分配两个初始堆段:一个用于小型对象(小型对象堆或 SOH),一个用于大型对象(大型对象堆,每个对象都大于85000字节)。
GC执行阶段(触发垃圾回收后)
1、GC首先挂起所有线程,再判断要回收哪些代,然后应用程序的线程恢复允许。
如果回收第第一代或者第0代那么一切如常进行,如果要回收第二代,就会增加第0代的大小(超过其预算),以便再第0代中分配新对象。然后应用程序的线程恢复允许。
开始一次垃圾回收时候,GC会检查第一代(有过第一代)占用了多少内存,如果第一代远少于预算(内存空间),那么GC只检查第0代的对象。GC 将寻找存在的对象并将它们压缩。 但是由于压缩费用很高,GC 会扫过 LOH,列出没有被清除的对象列表以供以后重新使用,从而满足大型对象的分配请求。 相邻的被清除对象将组成一个自由对象。
2、构建不可达对象。目的是为了找出哪些可以删除,哪些不能删除。
GC运行一个普通的线程优先级的后台线程来查找不可达对象,找到之后再挂起所有线程。
(1)GC标记为“0”阶段。假定全部都可以删除。GC首先假定堆中的所有对象都是不可达unreachable(没有被人应用)的,然后CLR遍历堆中的所有对象,将同步索引字段中的一位设定为0,表示所有对象都因删除
(2)CLR检查所有的活动根,查看它们引用了哪些对象(这就为什么CLR的GC称为引用跟踪GC的原因)如果一个根包含null,CLR忽略这个根并继续检查下个根。
任何根如果引用了堆上的对象,CLR都会标记那个对象,也就是将该对象的同步块索引中的位设为1。一个对象被标记后,CLR会检查那个对象中的根,标记它们引用的对象。如果发现对象已经标记,就不重新检查对象的字段。这就避免了因为循环引用而产生死循环。
标记对象的工作有两种模式:
- 非并发(同步) :标记工作开始之处,就暂停所有线程,开始标记工作。在CLR启动GC之前,除了触发垃圾回收的线程以外的所有托管线程均会挂起。目的是防止线程在clr检查期间访问对象并修改其状态。
- 后台(并发) :起一个低优先级的线程执行标记和回收工作,直到找到有为0的对象,再暂停所有线程,进行垃圾回收工作 在 .NET Core 中,服务器/工作站垃圾回收既可以是非并发也可以是后台执行。 后台工作方式只影响第 2 代中的垃圾回收;第 0 代和第 1 代中的垃圾回收始终是非并发的,因为它们完成的速度很快。
(3) 在标记完栈中根指向的可达对象后。GC开始标记GC句柄表和GC终结列表中的根指向的可达对象,具体如下:
1、然后垃圾回收器扫描appDomain 的GC句柄表中保护Normal、pinned标记的项,将他们当作根来处理,同时标记执行项目的所引用的对象(已经这些对象的内部字段所引用的对象)。
2、扫描appDomain 的GC句柄表中wesk记录项。如果weak记录项引用了未标记的对象,该引用标识就是不可达对象。该记录项的引用值改为null。
3、GC扫描终结列表,如果发现垃圾中有被Finalization Queue中的指针所指向的对象,则将这个对象从垃圾中分离出来,并将指向它的指针移动到Freachable Queue中。这个过程被称为是对象的复生。在GC压缩后将复活的对象提升到较老的一代,一个特殊的高优先级CLR线程,执行每个对象的Finale方法,最后清空Freachable队列。下一代垃圾回收时,发现以终结的对象成为真正的垃圾。可终结对象需要执行两次的垃圾回收才能释放它们的占用的内存。
4、weakTrackResurrection不理解 基本用不到
5、GC对内存进行压缩,填补不可达对象留下的内存空洞,这其实就是一个内存碎片整理的过程。Pinned对象不会压缩(移动),垃圾回收器会移动它周围的其他对象。
应用程序的根包含线程堆栈上的静态字段、局部变量、CPU 寄存器、GC 句柄和终结队列。
可达(reachable)
已标记的对象不能被垃圾回收,因为至少有一个根在引用它。我们说这种对象是可达(reachable)的,因为应用程序代码可通过仍在引用它的变量抵达(或访问)它。
不可达(unreachable)
未标记的对象是不可达(unreachable)的,因为应用程序中不存在使对象能被再次访问的根。
4、GC的压缩(compact)阶段
删除未标记的,然后把可达的对象整到一起形成连续可用的内存空间。整理好对象的内存地址发生变化。不会压缩大对象。AppDomain中的GC句柄表用pinned标记的项也不会移动。
5、修正根的引用。CLR还有将每个根的地址减去整合后偏移的字节数,保证根的地址指向正确内存对象。
6、重置托管堆的NextObjPtr指针。指向最后一个幸存对象之后的位置。
7、CLR恢复所有线程。
如果CLR在一次GC之后回收不了内存,而且进程中没有空间来分配新的GC区域,就说明该进程的内存已耗尽。此时,试图分配更多内存的new操作符会抛出OutOMemoryException。应用程序可捕捉该异常并从中恢复。但大多数应用程序都不会这么做:相反,异常会成为未处理异常,Windows将终止进程并回收进程使用的全部内存。
8、汇总这次清除的结果,自动调优。垃圾回收后会检测有各代的多少内存被回收,多少对象幸存,垃圾回收器会根据应用程序的要求的内存负载自由优化。增大或者减小这些代的预算、增加或减少回收的次数。
【C# .Net GC】垃圾回收算法 应用程序线程运行时,的更多相关文章
- Java GC 垃圾回收算法 内存分配
垃圾回收(Garbage Collection, GC)是Java不同于c与c++的重要特性之一. 他帮助Java自动清空堆中不再使用的对象. 由于不需要手动释放内存,程序员在编程中也可以减少犯错的机 ...
- gc垃圾回收算法原理
目录 三色标记法 标记-清扫(Mark And Sweep)算法 标记-清扫(Mark And Sweep)算法存在什么问题? 三色并发标记法 gc和用户逻辑如何并行操作? 进程新生成对象的时候,GC ...
- GC垃圾回收算法
什么是GC垃圾回收呢.日常生活中我们去餐厅吃饭吃完饭,吃完饭走了餐具不用管,服务员在把餐具拿走,这是一种方式,服务员怎么知道他要来把餐具拿走呢,因为你走了,这个位置空了.服务员什么时候拿走餐具很重要, ...
- 6.GC垃圾回收算法和垃圾收集器的关系
JAVAGC垃圾回收机制和常见垃圾回收算法 推荐博客:JVM垃圾回收机制和常见垃圾回收算法 JVM的内存结构.垃圾回收算法
- GC: 垃圾回收算法
标记-清除算法标记-清除(Mark-Sweep)算法是最基础的算法,就如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象.之所以说 ...
- JavaScript深入浅出第3课:什么是垃圾回收算法?
摘要: JS是如何回收内存的? <JavaScript深入浅出>系列: JavaScript深入浅出第1课:箭头函数中的this究竟是什么鬼? JavaScript深入浅出第2课:函数是一 ...
- 小师妹学JVM之:GC的垃圾回收算法
目录 简介 对象的生命周期 垃圾回收算法 Mark and sweep Concurrent mark sweep (CMS) Serial garbage collection Parallel g ...
- JVM中的垃圾回收算法GC
GC是分代收集算法:因为Young区,需要回收垃圾对象的次数操作频繁:Old区次数上较少收集:基本不动Perm区.每个区特点不一样,所以就没有通用的最好算法,只有合适的算法. GC的4大算法 1.引用 ...
- A6. JVM 垃圾回收算法(GC 算法)
[概述] 常见的垃圾回收算法有:标记-清除算法.复制算法.标记-整理算法.分代收集算法. [标记-清除算法] 标记-清除算法是最基础的收集算法,如同它的名字一样,算法分为 “标记” 和 “清除” 两个 ...
随机推荐
- Android开发之事件
当按下一个按钮时,有两种事件促发的方式,一种是通过回调,一种是通过事件监听. 回调: xml中: 只要设置android:onclick="回调函数名字" '主函数中重写回调函数即 ...
- 写react项目需要注意的
key应该是稳定的,且唯一的,尽量不要用索引作为key 都知道React组件渲染列表时需要为每个列表元素分配一个在列表中独一无二的key,key可以在DOM中的某些元素被增加或删除视乎帮助React识 ...
- vi与vim编辑器与解决vim编辑异常
目录 一:vi与vim编辑器 二:解决vim编辑异常 一:vi与vim编辑器 vim是vi的升级版编辑器,就是vim比vi丰富一些. 1.安装vim 命令 yum install vim -y 2.打 ...
- python使用range()函数创建数字列表list
#!/usr/bin/python #coding=utf-8 #好好学习,天天向上 numbers=list(range(1,6)) print(numbers) range指定步长: #!/usr ...
- kubernetes之手动部署k8s 1.14.1高可用集群
1. 架构信息 系统版本:CentOS 7.6 内核:3.10.0-957.el7.x86_64 Kubernetes: v1.14.1 Docker-ce: 18.09.5 推荐硬件配置:4核8G ...
- python 小兵(1)
变量规则 1.只能以数字,字母,下划线命名 2.不能使用数字开头 3.不能使用python关键字 4.不建议用拼音或中文 5区分大小写 6推荐使用驼峰,下划线 全部大写是常量 注释 # 单行注释 (当 ...
- .NET Core分析程序集最优美的方法,不用Assembly.LoadFile(),超越ReflectionOnlyLoad
在编写.NET程序的时候,如果需要对一个程序集文件进行分析,我们可以使用Assembly.LoadFile()来加载这个程序集,然后对LoadFile()方法返回的Assembly对象进行进一步的分析 ...
- attachEvent
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- War包是什么??
感谢大佬: https://blog.csdn.net/Stitch__/article/details/88091745 https://www.jianshu.com/p/3b5c45e8e5bd ...
- 版本控制SVN
为什么需要版本控制软件 代码的冻结 避免在重大的考核之前改动代码 每个稳定版本都在服务器保存进度,随时可以回退 需求频繁的变化不要改动稳定的代码,不要改别人写好的代码 为什么需求会变化?有时候产品自己 ...