垃圾回收器GC

3/3/2022 12:11:58 AM
635
0

CLR初始化时,会为每一代选择内存预算。托管堆只支持三代:0、1、2 总共三代。

所有新分配的对象都会进入托管堆的第0代内存空间,当达到第0代内存预算边界时会启用GC对没有被引用的对象回收。

那些没有被回收掉的对象会进入到第1代的内存空间,此时要进行内存压缩,使第一代中的对象占用的内存地址连续。

1、新生对象全部进入到第0代空间

2、0、1、2 达到预算边界会启动GC进行垃圾回收

3、GC垃圾回收会对0,1的内存压缩,使对象占用地址连续

4、GC启动时会先停止其他所有线程

5、第1代空间内被GC回收后剩余的对象会进入第2代空间

6、GC对第x代进行回收后发现有大量对象存活,没有多少内存被回收,就会增大第0代的预算

7、如果没有回收到足够多的内存,GC会执行一次完整的回收。如果还不够则抛出OutOfMemeoryException异常

8、如果GC对第x代回收后发现存活的对象很少后,会减少第0代的预算,空间的减少意味着GC回收的更频繁

9、代码显式的调用GC.Collect也会触发垃圾回收

10、window 报告内存过低也会出发GC

11、CLR卸载AppDomain也会触发GC

12、CLR正在关闭也会触发GC,此时CLR不会试图压缩或释放内存。整个进程的内存都将被操作系统回收

13、大对象(>85000字节)不在小对象的地址空间(1-12所述)分配,而是在进程地址空间的其他地方分配

14、GC不压缩大对象,因为内存中移动他们代价过高。

15、大对象总是在第二代空间存储

16、CLR在启动时候会启动一个GC工作模式,进程中之前该模式不会改变

17、GC的两个模式:工作站(客户端)、服务器

18、如果服务器应用程序在单处理器机器上运行GC总是以工作站模式运行

19、GC支持两种子模式:并发(默认)、非并发。并发模式下垃圾回收器有一个额外的后台线程,它能在应用程序运行时并发标记对象。

20、析构函数:在对象被回收之前执行的代码。解决对象被回收前需要释放对象占用的其他资源,比如对象占用的IO资源

21、被视为垃圾的对象给在垃圾回收完毕后才会调用析构函数Finalize

22、析构函数执行可能会需要对象访问字段,这导致了对象存活时间边长,增大内存空间消耗,所以应尽可能避免析构函数(待扩展)

23、析构函数执行时间无法控制,GC完成后才会运行Finalize(与21重复)

24、待续……

全部评论



提问