C#垃圾回收机制的详细介绍
程序员文章站
2023-12-21 13:58:04
一、托管代码/非托管代码c#代码通过c#编译器编译成程序集,程序集由微软中间语言组成,clr会为程序集开辟一个应用程序域,程序集就是运行在这个应用程序域里面的,应用程序域是...
一、托管代码/非托管代码
c#代码通过c#编译器编译成程序集,程序集由微软中间语言组成,clr会为程序集开辟一个应用程序域,程序集就是运行在这个应用程序域里面的,应用程序域是相互独立的,互不影响。
托管代码:被clr管理的代码。
非托管代码:不被clr管理的代码。
分配在栈空间的变量,一旦执行完成其所在的作用域(即大括号范围)就会被clr回收。
分配在堆里面的对象,当没有任何变量引用它的时候,这个对象就被标记为“垃圾对象”(没有变量引用它),等待垃圾回收器回收。
eg:
复制代码 代码如下:
person p=new person();
p=null;//p这时候没有指向任何对象空间,此时为“垃圾对象”。
二、gc
gc会定时清理堆里面的垃圾对象,gc的清理频率程序员无法决定,clr会自动控制。当一个对象标记为垃圾的时候,这个对象不一定会被立即回收。
三、析构函数
1、不能有访问修饰符,不能有参数。
2、在对象被垃圾回收器回收的时候,析构函数被gc自动调用。
3、执行一些清理善后的操作的时候。
复制代码 代码如下:
class person
{
~person()
{
console.wrilteline("我是析构函数");
}
}
四、代
当堆里面的对象有1w个的时候,gc是不是循环1w次来判断是否为“垃圾对象”,然后对其进行回收呢?答案是否定的,微软根据实际需要采用了很多种算法来清理堆里面的垃圾对象,其中很重要的一种算法就是“代”。堆里面总共有3代,譬如,当程序运行时,有对象需要存储在堆里面,gc就会创建第1代(假设空间大小为256k),对象就会存储在第0代里面,当程序继续运行,运行到第0代的大小不足以存放对象,这时候就就会创建第1代(假设空间为10m),gc就会把第0代里面的“垃圾对象”清理掉,把“活着”的对象放在第1代,这时候第0代就空了,用于存放新来的对象,当第0代满了的时候,就会继续执行以上操作,随着程序的运行,第1代不能满足存放要求,这时候就会创建第2代,清理方式如上相同。下图用于理解以上描述的过程:
gc.getgeneration(p)得到指定的对象对应的代,总共有三代。
gc.collect();//让垃圾回收器对所有的代进行回收。
gc.collect(1)//回收第0代和第1代回收。
复制代码 代码如下:
class program
{
~program()
{
console.writeline("我是析构函数");
}
static void main(string[] args)
{
program p1 = new program();
console.writeline("p对象所在的代:" + gc.getgeneration(p1));//处在第0代
gc.collect();//所有代清除了,包括第0代,这时候存活的对象就存在在第1代了。
console.writeline("p对象所在的代:" + gc.getgeneration(p1));
gc.collect();//所有代清除了,包括第0代第1代,这时候存活的对象就存在在第2代了。
console.writeline("p对象所在的代:" + gc.getgeneration(p1));
gc.collect();//最多只有3代
console.writeline("p对象所在的代:" + gc.getgeneration(p1));
p1 = null;//p这时候在第2代了
gc.collect(2);//这时候p1就被回收掉了。
console.readkey();
}
}
结果: