C# GC
一 GC(垃圾回收)的概念
了解:创建对象的主要流程
- 计算要分配的内存大下
- 向GC堆申请内存
- 检查GC堆的NextObjPtr(0代GC堆)后面内存是否足够
- 内存不足就触发一次0代垃圾回收
- 分配内存,后移NextObjPtr指针,使之永远指向下一个可用地址
- 调用构造函数
1.1堆与GC
- 加载堆:盛放了静态类型及成员,程序运行的任何时候都不可能是垃圾,不受GC管辖
- GC堆:GC只负责GC堆的清理。GC堆初始化时有阈值,256K,2M,10M,可动态调整。
- 大对象堆:2代GC堆一部分,不会轻易回收,对象太大,移动复制成本高。
注意:
- 大部分情况,自动GC只对0代起作用,(其它代满也会)回收后的对象,存活下来的,会升代
- 代的数目太多时,导致0代空间变小,更容易满,会令自动GC更容易触发,升代更频繁
1.2识别垃圾
了解局部性原理:时间局部性,空间局部性
垃圾定义:没有被其它任何资源引用的资源。
判别方法(常用的):
- 引用计数法:在任何时候,维护任意一个类型的引用数。若该数为0,视为垃圾。
- 标记法:需要GC时,建立一张引用有向图,从若干起点开始遍历,无法到达的对象皆为垃圾。
引用计数法
引用计数法的优点:
- 实时垃圾处理:引用数变为0时(即成为垃圾的那一刻),立即回收
- 垃圾回收性能很高:一次仅操作一个对象(与标记法相比)
缺陷:无法解决循环引用
循环引用:数个对象互相引用对方,形成一个环,以至于引用始终不为0,无法被GC清理。
优化:弱引用(了解)
标记压缩法
处理步骤
- 标记:为堆上所有的对象建立一个有向图,垃圾收集器可以检测到所有的孤岛,将他们标识为垃圾。(主要:根引用,根指针列表,根不会为垃圾,发现标记过即为循环引用)
- 压缩:将非垃圾对象进行移动,使得堆中的空间尽量连续。(GC时,所有线程停止工作:压缩时,对象的指针会暂时指向无效地址,可能指针悬挂)
优点
解决循环引用
缺点
无法做到实时清除
注意:C#使用标记压缩法
触发GC的情况
- 0代没有足够空间
- 主动调用了GC.Collect(可以指定代)
- 卸载AppDomain
- Windows报告内存不足
二垃圾回收策略
垃圾回收的一般方式:
- Dispose方法和IDispose接口(非托管的第一道闸):通过继承IDispose接口,并实现Disposible方法,可以对托管和非托管资源进行回收。当类型中含有非托管资源或者实现了Disposible,才需要继承IDisposible接口。
- 析构函数(Finalize的语法糖)(终结器)(非托管的二道闸,结构体除外):在类型中含有非托管时才需要实现析构函数。声明析构函数的唯一目的是回收非托管资源。:如果类型中有非托管资源,却没有实现析构函数,有没有调用Dispose,则当GC回收这个类型时(通过Finalize),将只会回收托管资源(非托管资源没有FInalize方法),非托管资源将会一直存留在堆中。
可终结对象的复生及避免:
可终结对象:若一个对象拥有Finalize方法,那这个对象就被认为是可终结的。终结该对象时,会调用他的Finalize方法。调用者是一个优先级较高的线程。
直接上图:
一轮GC之前,终结列表不是根,否则,C无法被GC掉,现在,C是垃圾
一轮GC之后,C不是垃圾,因为被freachable队列中的一个对象引用,而freachable队列是一组根
#空间换时间
移到freachable队列时:
- 是为了保证调用Finalize方法,复生是他的副作用
- 发生在标记阶段
- 当reachable队列出现任何记录时,执行该记录的Finalize方法。
#可终结队形至少能存活两轮GC.
#解决方法:主动调用Dispose方法,Dispose方法成功执行之后,调用GC.SuppressFinalize告诉GC不需要再去调用这个对象的Finalize.
#另:GC.ReRegisterForFinalize方法,可以将对象放入freachable队列中。(成为不死C)
回收托管和非托管资源
都基于垃圾回收的一般方式。
非托管有Dispose模式。
#详解:《C#从现象到本质》p142
using关键字
使用using关键字可以保证对象离开using块时,CLR会自动调用他的Dispose方法,所以,显然,using只能用于那些实现了IDisposible接口的对象。
using会被编译为try-finaly块,在finaly中调用Dispose方法。
我们不需要手动调用Dispose对象,只要代码离开using块,自动调用Dispose方法。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示