Net-GC垃圾回收

2021-03-26 01:24

阅读:537

标签:col   过程   next   http   垃圾回收   静态   cpu   新生代   文件   

1对象的分配

CLR要求所有的对象都是从托管堆分配。

CLR划出一个地址空间区域作为托管堆。

CLR还要维护一个指针,NextObjPtr。 用来指向下一个对象在堆中分配的位置。

技术图片

 

 

 

一个区域被非垃圾对象填满,CLR会分配更多的区域。一直重复,直到整个进程的地址空间被填满。所以你的应用程序受进程的虚拟地址空间限制。

32位-1.5GB

64位-8TB。

1.1对象的分配过程

1.计算类型的字段(包括基类继承的字段成员)所需的字节数

2. ***加上对象的开销所需的字节数***。

         a类型对象指针(属于哪个类)

         b同步块索引 (线程同步所需,垃圾回收使用)

         (32位程序,这两个字段各许32位,一共8个字节)

         (64位程序,这两个字段各需64位,一共16个字节)

3.CLR检查区域是否够大,如果够大就在NextObjPtr指针指向的地址放入对象。

 同时将指针向后移动。

此处有个优化点:CPU从内存中读取数据,是成页读取的,连续分配则能减少CPU读取内存的次数。

如果一直分配的话,可能很快将内存占用满,所以需要GC来回收内存。--垃圾回收

 

2垃圾回收算法

当new对象的时候,发现没有足够的地址空间来分配对象,则CLR就执行垃圾回收。

事实上是在第0代满的时候就会执行GC。

2.1垃圾回收的算法

根:我们将所有引用类型的变量都称之为 根。

在CLR执行GC的时候,会暂停进程中的所有线程。防止线程在CLR检查期间访问对象并改变其状态。然后CLR进入标记阶段。

标记阶段:

CLR遍历所有对象,将同步块索引中的一位设为0。表示所有对象都应删除。

然后检查所有的活动根,查看他们引用了哪些对象,任何根如果引用了堆上的对象,CLR就会标记这个对象,将同步块索引中的位设为1。

一个对象被标记后,CLR会检查对象中的根,标记他们引用的对象。如果发现对象已经被标记,就不重复检查对象的字段,避免循环引用。

一次垃圾回收过程,标记为0的对象就应该被收回。

技术图片

 

 

 

OutOfMemeryException异常:当内存耗尽,还要进行new或者进行对象分配时,会抛出该异常。---比如死循环。

内存泄漏

一个常见的原因就是:静态字段引用了集合对象,然后不停的向集合添加数据项。静态字段中对象一直存活,垃圾回收不掉,导致内存泄漏。因此,应尽量避免使用静态字段。

2.2代:提升性能

垃圾回收中的代:0代,1代,2代。GC.MaxGeneration

0代为新生代,2代为最老的代。

新创建的对象都是0代。

CLR会在内存中分配固定大小的代。0代多大,1代多大,2代多大。

 

过程:

如果0代内存已满,进行GC,标记阶段,不可达的或者说没有引用的标记为0.并从内存中移除

技术图片

 

 

 

将正在使用的对象标记为1,并转移到1代区域,

技术图片

 

 

 

同理,CLR会对第1代进行内存分配,当第0代满时,进行GC,0代移动到1代,1代满时,对1代区域进行回收,发现没有可回收对象时,将1代转移到2代,0代转移到1代,0代空出来。

如果第0代全是垃圾的时候,只需要将NextObjPtr指针指向内存头部即可,不必进行垃圾回收。

优化:其实如果垃圾回收了第0代,发现还有许多对象存活,没有多少内存被回收,就会增大0代预算。0,1,2代预算都可以被优化,增大或者缩小预算。

 

2.3垃圾回收触发条件

出发垃圾回收的条件:

l  代码显示调用GC.Collect()方法

l  Windows报告内存过低

l  CLR正在卸载AppDomain

l  CLR正在关闭

 

以上都是小对象

2.4大对象

85000字节或者更大的对象。

GC不压缩大对象,因为移动大对象代价过高。

大对象总是在2代,不可能放到0或1代。

大对象一半是大字符串 XML或JSON或者用于IO操作的字节数组(比如从文件或者网络将字节读入缓冲区以便处理)

 

Net-GC垃圾回收

标签:col   过程   next   http   垃圾回收   静态   cpu   新生代   文件   

原文地址:https://www.cnblogs.com/alua/p/12643770.html


评论


亲,登录后才可以留言!