本章将和大家分享.NET中的GC垃圾回收。
托管堆垃圾回收--CLR提供GC。
1、什么样的对象需要垃圾回收?
托管资源+引用类型
托管资源和非托管资源:
托管的就是CLR控制的,例如:new的对象、string字符串、变量等;
非托管不是CLR能控制的,例如:数据库连接、文件流、句柄、打印机连接等;
using(SqlConnection)--被C#封装了用来管理那个非托管的数据库连接资源;
只要是需要手动释放的,都是非托管的。
2、哪些对象的内存,能被GC回收?
对象访问不到了,那就可以被回收了
程序--入口--去找对象--建立对象图--访问不到的就是垃圾。
3、对象是如何分配在堆上?
连续分配在堆上面,每次分配就先检查空间够不够。
4、什么时候执行GC?
a、new对象时--临界点
b、GC.Collect 强制GC
c、程序退出时会GC
a="123"
a=null
GC.Collect 可以GC,但是频繁GC是不好的,GC是全局的。
如果项目中有6个小时才运行new一次,什么时候GC? 这6个小时都不GC,可以手动GC。
5、GC的过程是怎么样的呢?
N个对象--全部对象标记为垃圾--入口开始遍历--访问到的就标记可以访问(+1)--遍历完就清理内存--产生不连续内存--压缩--地址移动--修改变量指向--所以会全局阻塞。
清理内存分2种情况:
a、无析构函数,直接清理内存。
b、把对象转移到一个单独的队列,会有个析构器线程专门做这个(清理慢一些)通常在析构函数内部是用来做非托管资源释放,因为CLR肯定会调用,可以避免使用者忘记的情况。
6、垃圾回收策略
对象分代:3代
0代:第一次分配到堆,就是0代
1代:经历了一次GC,依然还在的
2代:经历了两次或以上GC,依然还在的
垃圾回收时,优先回收0代,提升效率,最多也最容易释放。
0代不够---找1代---1代不够才找2代--再不够就不够了。。
大对象堆,没有分代,直接都是2代,80000字节以上就叫大对象。
大对象堆没有分代这主要有2个原因:一是内存移动时如果是大对象则很耗资源;二是0代空间问题;
7、标准Dispose模式
using System;namespace MyGC{ /// <summary> /// 标准Dispose模式 /// /// 析构函数:被动清理 /// Dispose:主动清理 /// </summary> public class StandardDispose : IDisposable { /// <summary> /// 演示创建一个非托管资源 /// </summary> private stri.........