理解.NET内存回收机制

2018-09-11  本文已影响0人  三岁能抬头

前言

说来真是好笑,我只是想了解值类型和引用类型,结果跳出来一大堆我本不该承受的东西。

线程

每个正在运行的程序都对应着一个进程(process),在一个进程内部可以有一个或多个线程(thread)

堆栈和堆

每个线程都拥有一块“自留地”,称为“线程堆栈”,大小为1M用于保存自身数据。
这里分为两个概念,根据 数据类型 的不同分为 堆栈,这里的堆在.NET中叫 托管堆,其实是同一个东西,因为使用基于.NET CLR的编译器开发的代码叫托管代码,所以...

内存分配类型

两种:

public void Method1()  
{  
    // Line 1  
    int i=4;  
    // Line 2  
    int y=2;  
    //Line 3  
    class1 cls1 = new class1();  
}

步骤:

  1. 执行第一行,编译器分配一小块叫堆栈的内存。
  2. 执行第二行,编译器分配的内存堆叠在第一块内存的顶部。指针总是指在最后一块内存的后面一个位置
    注:内存分配和释放使用的是LIFO(Last in first out,后进先出)逻辑。
  3. 执行第三行,创建对象时,它在堆栈上创建一个指针可以理解为路径,真实对象的内容储存在叫堆的内存中。
    4.当退出这个方法时,分配到堆栈上的所有内存变量被清除,所有与int数据类型关联的变量以LIFO方式从堆栈中接触分配。

关系如图:


垃圾回收器

既然提到堆的话必须说一下这个垃圾回收器GC,因为堆内存的分配需要通过Garbage Collector(垃圾回收器:GC)解除分配。
垃圾回收器在后台做什么呢?
为了知道内存的分配的,GC以根对象全局:应用程序(包括:静态或处于活动中的局部变量以及寄存器指向的对象)为根目录找到下级的内存分配地址,并记录下来“绘制”对象列表根对象直接或间接引用的对象列表,其他没在列表的将被释放,如果内存分配有更新,对象列表也会更新。

生存期垃圾回收

垃圾回收器将内存分为多个托管堆,每个代表一种生存期等级GC支持三个等级(0级、1级、2级)
值得一提的是,这个等级划分存在一个规则:

流程:当应用程序创建对象时,这些对象首先被放在0级对象列表中,当0级列表满了,GC开始释放内存资源如上所说把应用程序不引用的对象删除。如果不能在0级删除,那么该对象被提升等级,依次类推.Net运行时支持的最大级是2级...
那么未处理的对象越多,托管堆的大小随之增大,因此可能存在性能问题。

终结器-Finalize()

为什么对象会等级提升,我们来看看处理器的步骤:

  1. 新对象创建,对象被放入0级托管堆。
  2. 当0级列表填满时,GC运行并清理内存。
  3. 如果对象没有析构函数C#编译器会把析构函数翻译(重命名)为终结器finalize()并且不被引用,那么GC把它们清除;如果有,GC把它们放入终结队列中之后移到Freachable队列等级提升中并在下一次迭代中执行每个对象的Finalize方法。
  4. 当Finalize方法执行之后被标识可回收释放掉。

那么在调用Finalize方法时,对象执行方法使对象可达,那么该对象将复活。

简单的说有析构函数的对象会在内存中存活的时间更长

.Net提供IDisposable接口

class clsMyClass : IDisposable
{ 
  public clsMyClass()
  { 
  }
  ~clsMyClass()
  {
  }

  public void Dispose()
  {
    GC.SuppressFinalize(this);
  } 
}

这里“SuppressFinalize”指示GC不要调用Finalize方法,所以不会发生GC的二次调用。

引文

END

上一篇 下一篇

猜你喜欢

热点阅读