C#.NET GC.Collect垃圾回收机制详解
作者:作者不详  发布日期:2020/04/09 15:51:20
  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



这里必须知道,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




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




C/S框架网|原创精神.创造价值.打造精品

扫一扫加微信
C/S框架网作者微信 C/S框架网|原创作品.质量保障.竭诚为您服务

上一篇 下一篇