C#.NET GC.Collect垃圾回收机制详解
C#.NET GC.Collect垃圾回收机制详解
扫一扫加微信
什么是GC?
GC如其名,就是垃圾收集,当然这里仅就内存而言。Garbage Collector(垃圾收集器,在不至于混淆的情况下也成为GC)以应用程序的root为基础,遍历应用程序在Heap上动态分配的所有对象[2],通过识别它们是否被引用来确定哪些对象是已经死亡的、哪些仍需要被使用。已经不再被应用程序的root或者别的对象所引用的对象就是已经死亡的对象,即所谓的垃圾,需要被回收。这就是GC工作的原理。
GC的必要性
1)、应用程序对资源操作,通常简单分为以下几个步骤:
为对应的资源分配内存 → 初始化内存 → 使用资源 → 清理资源 → 释放内存
2)、应用程序对资源(内存使用)管理的方式,常见的一般有如下几种:
[1] 手动管理:C,C++,Pascal
[2] 计数管理:COM,Pascal
[3] 自动管理:.NET,Java
3)、但是,手动管理和计数管理的复杂性很容易产生以下典型问题:
[1] 程序员忘记去释放内存
[2] 应用程序访问已经释放的内存
产生的后果很严重,常见的如内存泄露、数据内容乱码,而且大部分时候,程序的行为会变得怪异而不可预测,还有Access Violation等。这个情况在C++、Pascal语言非常常见。
.NET、Java等给出的解决方案,就是通过自动垃圾回收机制GC进行内存管理。这样,问题1自然得到解决,问题2也没有存在的基础。
4)、法自动化的内存管理方式极容易产生bug,影响系统稳定性。
什么是代(Generation)?
代(Generation)引入的原因主要是为了提高性能(Performance),以避免收集整个堆(Heap)。
一个基于代的垃圾回收器做出了如下几点假设:
1、对象越新,生存期越短;
2、对象越老,生存期越长;
3、回收堆的一部分,速度快于回收整个堆。
.NET的垃圾收集器将对象分为三代(Generation0,Generation1,Generation2),不同的代里面的内容如下:
1、G0 小对象(Size<85000Byte):新分配的小于85000字节的对象。
2、G1:在GC中幸存下来的G0对象。
3、G2:大对象(Size>=85000Byte);在GC中幸存下来的G1对象。
C# Code:
object o = new Byte[85000]; //large object
Console.WriteLine(GC.GetGeneration(o)); //output is 2,not 0
//来源:C/S框架网 | www.csframework.com | QQ:23404761
Console.WriteLine(GC.GetGeneration(o)); //output is 2,not 0
//来源:C/S框架网 | www.csframework.com | QQ:23404761
这里必须知道,CLR要求所有的资源都从托管堆(managed heap)分配,CLR会管理两种类型的堆,小对象堆(small object heap,SOH)和大对象堆(large object heap,LOH),其中所有大于85000byte的内存分配都会在LOH上进行。
代收集规则:当一个代N被收集以后,在这个代里的幸存下来的对象会被标记为N+1代的对象。GC对不同代的对象执行不同的检查策略以优化性能。每个GC周期都会检查第0代对象。大约1/10的GC周期检查第0代和第1代对象。大约1/100的GC周期检查所有的对象。
代是指托管内存中不同的区域,对象越老位于的代越靠后,比如:第一次垃圾回收后某个对象未被回收,它可能就会从0代移动到1代,以此类推。
何谓垃圾?
垃圾就是只没有任何对象再和他有引用关系,专业点说就是从这个对象开始找其引用,一直找,如果找到它正在引用一个根,那么这个就是不是垃圾,如果找不到根则这个对象就是垃圾。
什么是根(Root)?
根就是指一个存储位置,包含指向某个引用类型的指针。比如静态变量,全局变量就是根,当前寄存器里面的对象就是根,还有当前调用栈上的参数,局部变量都是根。
另外,垃圾回收开始的时候当前所有线程都将被挂起,开始收集托管堆上的垃圾,收集完了还要压缩内存,然后等待垃圾回收结束以后再恢复这些线程,从这个角度来说,还是少调用垃圾回收,但是不是不能调,要视情况而定。
每个应用程序都包含一组根(root)。每个根都是一个存储位置,其中包含指向引用类型对象的一个指针。该指针要么引用托管堆中的一个对象,要么为null。
在应用程序中,只要某对象变得不可达,也就是没有根(root)引用该对象,这个对象就会成为垃圾回收器的目标。
用一句简洁的英文描述就是:
GC roots are not objects in themselves but are instead references to objects. Any object referenced by a GC root will automatically survive the next garbage collection.
.NET中可以当作GC Root的对象有如下几种:
1、全局变量
2、静态变量
3、栈上的所有局部变量(JIT)
4、栈上传入的参数变量
5、寄存器中的变量
注意,只有引用类型的变量才被认为是根,值类型的变量永远不被认为是根。因为值类型存储在堆栈中,而引用类型存储在托管堆上。
什么时候发生GC
1、当应用程序分配新的对象,GC的代的预算大小已经达到阈值,比如GC的第0代已满;
2、代码主动显式调用System.GC.Collect();
3、其他特殊情况,比如,windows报告内存不足、CLR卸载AppDomain、CLR关闭,甚至某些极端情况下系统参数设置改变也可能导致GC回收。
GC.Collect()的一般用法如下面源码如示:
C# Code:
dpFormulaList.Clear();
dpFormulaList = null;
inputs.Clear();
inputs = null;
GC.Collect();
//来源:C/S框架网 | www.csframework.com | QQ:23404761
dpFormulaList = null;
inputs.Clear();
inputs = null;
GC.Collect();
//来源:C/S框架网 | www.csframework.com | QQ:23404761
C# Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TestDOME
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using(Demo de2 = new Demo())
{
de2.dt();
}
Demo de3 = new Demo();
de3.Dispose();
Demo1 d1 = new Demo1();
d1 = null;//设置为空时才可以手动释放
GC.Collect();
}
}
public class Demo : IDisposable//继承接口
{
public void dt()
{
}
~Demo()
{
Dispose(false);
}
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(true);
}
private bool _disposed = false;//资源释放标志
protected virtual void Dispose(bool disposeManageResourse)
{
if (!_disposed)
{
if (disposeManageResourse)
{
//释放托管资源
MessageBox.Show("回收资源1");
}
_disposed = true;
}
}
#endregion
}
public class Demo1
{
~Demo1()
{
MessageBox.Show("回收资源d1");
}
}
}
//来源:C/S框架网 | www.csframework.com | QQ:23404761
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TestDOME
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using(Demo de2 = new Demo())
{
de2.dt();
}
Demo de3 = new Demo();
de3.Dispose();
Demo1 d1 = new Demo1();
d1 = null;//设置为空时才可以手动释放
GC.Collect();
}
}
public class Demo : IDisposable//继承接口
{
public void dt()
{
}
~Demo()
{
Dispose(false);
}
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(true);
}
private bool _disposed = false;//资源释放标志
protected virtual void Dispose(bool disposeManageResourse)
{
if (!_disposed)
{
if (disposeManageResourse)
{
//释放托管资源
MessageBox.Show("回收资源1");
}
_disposed = true;
}
}
#endregion
}
public class Demo1
{
~Demo1()
{
MessageBox.Show("回收资源d1");
}
}
}
//来源:C/S框架网 | www.csframework.com | QQ:23404761
扫一扫加微信
版权声明:本文为开发框架文库发布内容,转载请附上原文出处连接
NewDoc C/S框架网