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、待续……
本文链接:https://blog.nnwk.net/article/66
有问题请留言。版权所有,转载请在显眼位置处保留文章出处,并留下原文连接
Leave your question and I'll get back to you as soon as I see it. All rights reserved. Please keep the source and links
友情链接:
子卿全栈
全部评论