前言:

在.NET程序开发中,为了将开发人员从繁琐的内存管理中解脱出来,将更多的精力花费在业务逻辑上,CLR提供了自动执行垃圾回收的机制来进行内存管理。开发人员甚至感觉不到这一过程的存在。CLR执行垃圾回收的过程,有以下几点:

  • 如何判断哪些对象是可以进行回收的,哪些是要保留的?
  • 对象在堆上是如何分布的?何时执行垃圾回收?
  • 垃圾回收的过程如何进行的?有哪些优化策略?

判断哪些对象需要进行回收

垃圾回收,第一步要判断哪些对象需要被GC回收掉。简而言之,那些在代码的任何位置也无法访问到的对象是需要被GC回收掉的。

GC借助于应用程序根(Application Roots)和对象图(Object Graph)来判断哪些对象需要被回收。应用程序根保存了堆上对象的引用,如果一个对象没有直接或者间接的被应用程序根所引用,那么就说明没有任何代码可以访问到它,因此这个对象可以被回收。

应用程序根只是一个入口点,一个对象可能持有其他一个或者多个对象的引用,这种对象间的引用关系构成了对象图。每次创建新对象,在复制引用、删除引用,或者执行垃圾回收之后,CLR都会自动更新它。

对象如何分配在堆上

.NET中的对象创建在托管堆上,托管堆维护着一个指针,这个指针标识了下一个将要创建的新对象所在位置,通常称作新对象指针。该指针总是位于托管堆的末尾。当使用new运算符创建对象时,CLR将会执行下面几个主要操作:

  • 计算此对象所要分配的内存大小;
  • 检查托管堆,确保托管堆有足够的空间来建立这个对象。如果空间够,将会调用构造函数来创建对象,并在托管堆末尾创建对象,然后返回对象在托管堆上的引用。引用的地址即为新对象指针所指向的地址。如果空间不够,则会执行一次垃圾回收来释放空间;
  • 修改新对象指针的值,使它指向上一个可用的地址。

垃圾回收的执行过程

GC有许多算法,常见的算法有Reference Counting, Mark Sweep, Copy Collection等,目前主流的虚拟系统.NET CLR, Java VM都采用的Mark Sweep算法。Mark-Sweep标记清除阶段:先假设Managed Heap中所有对象都可以被回收,然后找出不能回收的对象,给这些对象打上标记,最后Managed Heap中没有打标记的对象都可以被回收。Compact压缩阶段:对象回收之后Managed Heap内存空间变得不连续,在Managed Heap中移动这些对象,使他们重新从Managed Heap基地址开始连续排列。

执行垃圾回收的时机:

  • 当通过new关键字创建对象时,如果发现托管堆所占用的内存已经达到一个临界点,就会进行垃圾回收;
  • 应用程序退出时也会执行一次垃圾回收;
  • 调用System.GC.Collection()方法强制执行;

垃圾回收过程中的优化策略

垃圾回收过程中还采用了一些优化策略,主要时对象代(Object Generation)和大对象堆(Large Object Heap)

1. 对象代

对象共分了三个代级:

  • 第0代:新近分配在托管堆上的对象,从来没有被GC回收过,任何一个新对象,当它第一次被分配在托管堆上时,就是第0代;
  • 第1代:经历过一次垃圾回收后,依然保留在堆上的对象;
  • 第2代:经历过两次或者以上垃圾回收后,依然保留在堆上的对象。

当进行垃圾回收时,垃圾回收器将会首先检查所有的第0代对象,并对其中可回收的对象进行清理。如果清理后获得足够的空间,经历过垃圾回收后的对象将提升为第1代对象。

如果所有的第0代对象都检查过了,但是内存空间还不够,那么将会检查第1代对象的可访问性,并进行垃圾回收。此时,如果经历过垃圾回收的第1代对象仍保留在堆上,则会升级为第2代对象。类似的,如果内存仍不够用,将会对第2代对象进行检查和垃圾回收。如果第2代的部分对象在此次垃圾回收后仍然保留在堆栈上,它依然是第2代对象。因为总共定义了3代对象。如果第2代对象在进行完垃圾回收后空间依然不够用,则会抛出OutOfMemoryException异常。

可见,最容易清理掉的就是那些新对象。

2. 大对象堆

垃圾回收的过程中有一个很影响性能的地方,就是在压缩的过程中,因为要批量地挪动对象,以填充腾出来的空间,如果对象很大,那么要移动的数据量就会很大。

如果将大对象直接分配在第0代,那么第0代的空间很快就会被占满,从而迫使CLR执行一次垃圾回收,这样执行垃圾回收的次数就会变得很频繁。

因此,第二个优化策略就是采用大对象堆,当对象大小超过85kb时,就会被分配在大对象堆上。大对象堆有几个特点:

  • 没有代级的概念,所有对象都被视为第2代对象;
  • 不进行对象移动和空间压缩,因为移动大对象是相对耗时的操作。
  • 对象不会被分配在末尾,而会在链表中找合适的位置,因此会存在碎片问题。

至此,就对.NET GC有了一个基本的了解。感谢您的阅读~

[.NET] GC垃圾回收机制的更多相关文章

  1. JVM和GC垃圾回收机制和内存分配

    JVM运行期间 线程共享 线程私有 线程共享: 方法区 堆方法区:存放可以共享数据,静态常量,类的共有方法属性字段等,可以共享的存在方法区. 堆:存放class对象 . 线程私有:本地方法栈 虚拟机栈 ...

  2. JVM架构和GC垃圾回收机制

    深入理解系列之JDK8下JVM虚拟机(1)——JVM内存组成 https://blog.csdn.net/u011552404/article/details/80306316 JVM架构和GC垃圾回 ...

  3. java面试题之----JVM架构和GC垃圾回收机制详解

    JVM架构和GC垃圾回收机制详解 jvm,jre,jdk三者之间的关系 JRE (Java Run Environment):JRE包含了java底层的类库,该类库是由c/c++编写实现的 JDK ( ...

  4. 面试官,不要再问我“Java GC垃圾回收机制”了

    Java GC垃圾回收几乎是面试必问的JVM问题之一,本篇文章带领大家了解Java GC的底层原理,图文并茂,突破学习及面试瓶颈. 楔子-JVM内存结构补充 在上篇<JVM之内存结构详解> ...

  5. 乐字节Java|GC垃圾回收机制、package和import

    本文接上一篇:乐字节Java|this关键字.static关键字.block块.本文是接着讲述JavaGC垃圾回收机制.package 和 import语句. 一.GC垃圾回收机制 GC全名:Garb ...

  6. 通俗易懂.NET GC垃圾回收机制(适用于小白面试,大牛勿喷)

    情景:你接到xx公司面试邀请,你怀着激动忐忑的心坐在对方公司会议室,想着等会的技术面试.技术总监此时走来,与你简单交谈后.... 技术:你对GC垃圾回收机制了解的怎么样? 你:还行,有简单了解过. 技 ...

  7. GC垃圾回收机制详解

    JVM堆相关知识    为什么先说JVM堆?  JVM的堆是Java对象的活动空间,程序中的类的对象从中分配空间,其存储着正在运行着的应用程序用到的所有对象.这些对象的建立方式就是那些new一类的操作 ...

  8. C# GC 垃圾回收机制

    今天来谈谈C# 的GC ,也就是垃圾回收机制,非常的受教,总结如下 首先:谈谈托管,什么叫托管,我的理解就是托付C# 运行环境帮我们去管理,在这个运行环境中可以帮助我们开辟内存和释放内存,开辟内存一般 ...

  9. asp.net 之 GC (垃圾回收机制)

    今天抽时间好好整理了下GC相关知识,看了CSDN和博客园的几篇文章,有了一定的简单了解,决定根据个人理解整合一份随笔写下来,望诸位指教. 一:基础问题 1.首先需要知道了解什么是GC? GC如其名,就 ...

  10. GC垃圾回收机制,iOS内存管理。

    问题: MRC中通过调用静态方法创建的新对象,不再使用时需要对其发送release消息吗? 不需要,因为约定静态方法创建的对象会自动将其放入自动释放池,即已对其发送autorelease消息,因此不可 ...

随机推荐

  1. 使用caddy 进行nodejs web应用近实时编译更新

    caddy 相比nginx 是一个不错的轻量代理服务器,支持的功能也是比较多的, 同时插件也挺多 demo 测试的是通过git 插件进行一个使用spec-md 编写的文档近实时编译以及预览 项目使用d ...

  2. 便捷的Jenkins jswidgets

    很多时候我们在构建完成之后需要查看构建的状态,类似github 中的build Status 插件安装 搜索插件 使用 目前好像只支持自由项目的构建 代码集成 <!DOCTYPE html> ...

  3. deno学习一 安装试用&&几个问题解决

      基本的依赖可以参考github 我的环境是centos 7 基本安装 需要golang 以及yarn安装 Protobuf 3 这是官方的方式,实际可以变通下 cd ~ wget https:// ...

  4. stacks and queues--codility

    lesson 7: stacks and queues 1. Nesting 2. StoneWall 3. Brackets 4. Finsh lesson 7: stacks and queues ...

  5. CentOS下用yum配置php+mysql+apache

    环境: CentOS5.4  yum 想在一台CentOS的机器上安装配置支持dedeCMS的php+mysql+apache环境,把摸索的过程记录如下: 1. 安装Apahce, PHP, Mysq ...

  6. (5)函数式接口的简单使用之Predicate

    我们经常操作List,例如现在有一个功能要求在所有人中筛选出年龄在20岁以上的人. public class MyTest {     private final List<Person> ...

  7. Android Studio failed to create error code -6解决方法

    起因是AndroidStudio编译太慢,在stackoverflow上找解决方法,创建了个vm选项文件,导致内存不够用 很多中文博客上都千篇一律地说是内存不够,打开安装路径下bin目录下的studi ...

  8. [Android] 开发第九天

    以下代码完全使用代码来控制 UI 界面,不被推荐使用. package com.oazzz.test2; import android.graphics.LinearGradient; import ...

  9. Autofac框架详解

    一.组件 创建出来的对象需要从组件中来获取,组件的创建有如下4种(延续第一篇的Demo,仅仅变动所贴出的代码)方式: 1.类型创建RegisterType AutoFac能够通过反射检查一个类型,选择 ...

  10. CEP实时分析模型

    大数据量的实时分析场景: 股票实时分析系统:大数据量(基于内存),要求分析汇总数据