.Net的GC垃圾回收原理及实现

一、先了解下必备的知识前提

内存中的托管与非托管,可简单理解为:

托管:可借助GC从内存中释放的数据对象(以下要描述的内容点)

非托管:必须手工借助Dispose释放资源(实现自IDisposable)的对象

内存中有栈和堆的概念区分,仅简单说明:

栈:先进后出 的特点(这里不再详细阐述)

堆:存放数据对象实例的内存空间(以下要描述的内容点)

二、.Net GC的简单描述

GC垃圾回收是对于内存堆的处理过程。

当一个应用程序进程创建时,会为此应用程序在物理内存堆中分配一块虚拟的连续性内存空间,以供应用程序后续运行时存放产生的数据对象实例。

GC是一个独立的进程,用来自动维护管理内存堆中的空间分配和释放。它通过一个或多个线程进行垃圾回收,默认启用后台线程垃圾回收。(关于前台线程与后台线程,可参考其它)

三、.Net平台的GC垃圾回收,什么时候会被触发呢?

1、当被分配的堆中虚拟内存空间不够用时,系统会自动 回收/压缩/扩大 被分配的虚拟内存块,以适应新产生的数据对象存储。

2、当整个物理内存不够用时,系统会自动 回收/压缩 各个进程占用的内存空间,以适应新产生的数据对象存储。

3、当应用程序中手动触发GC回收时,GC按照手动指定的方式进行垃圾回收。

四、从作用域上 去理解堆中的代

先这样去理解吧

假设一个实例变量声明时的作用域较大,那它就不会马上被回收,因为作用域大的因素,有可能后续程序时常还会被用到。

假设一个实例变量声明时的作用域较小,那它就有可能被优先回收,因为生存周期较短,过了作用域范围,此变量不会再被使用。

假设一个静态的或全局的作用域变量,那它通常不会被回收,因为这样的全局声明会在任意代码段长期被使用。

所以,为了更好的回收,堆中将各数据对象实例归纳为:0代、1代、2代

0代:临时或最新创建的数据对象实例。最常被回收的对象实例。

1代:一段时间内再次使用的数据对象实例,生命周期较长的数据对象实例。较少被回收的对象实例。

2代:常住内存的对象实例,如:静态类型,全局作用域等的对象实例。通常为应用程序退出后回收。

五、堆中对象 在代之间的转移:幸存者的提升

应用程序持续运行中,

新创建的对象首先被放在0代中,当运行一段时间后,有些变量超出了自己所在的作用域,不会再被使用,会被GC清理;

由于有些变量作用域大,当前还未超出自己所在的作用域,接下来可能还会被使用,所以GC不会清理;

0代中,有些数据对象实例会被GC清理,有些数据实例对象未被GC清理,那么,未被GC清理的数据对象实例,我们称它为幸存者。

此时,0代中的幸存者会被转移到1代中(想想上面提到1代存放的是哪类对象实例...);

那么,以此类推,长期/处处被使用的对象实例,就会从1代中转移到2代中;

因此,2代中存放的通常为静态或全局作用域或长期被使用到的对象实例。

六、GC是如何去确定要清理的对象实例?

GC在堆中生成各对象间的结构图,作为回收对象的依据,找出非活动的对象。

所有数据对象实例之间的关联引用关系,都会生成一个完整的结构图,一些不在结构图中的 或超出所在作用域的 或不再被继续使用的对象实例,被称为非活动对象。被视为GC要清理的对象。

准确的说:

  • 堆栈根
  • 垃圾回收句柄
  • 静态数据

七、手动GC垃圾回收

在某些不常见的情况下,强制回收可提高应用程序的性能。在此,可使用 GC.Collect 方法强制执行垃圾回收,从而诱导垃圾回收。

注意,是诱导,而不是即刻回收。

为了考虑到应用程序当前的稳定运行,执行GC.Collect并不一定马上产生效果,这里仅仅是一个触发,会去收集将要回收的对象,回收动作会在未来某个合适的时间段进行。(当然,也可以强制阻塞式回收,这里略过)

(思考一下:无用的实例=null,是否告知GC为可回收的对象?再GC.Collect()后的效果。)

关于 GC.Collect 方法的参数,会用到上面提到的概念及场景:

  • 对指定的代进行回收
  • 指定回收次数
  • 强制回收 或 择机回收
  • 阻塞式回收 或 后台线程回收
  • 压缩 或 清理

(阻塞式回收方式:都先停一停,先让我回收完)

当然,通常建议:0代,择机,后台回收(阻塞式风险太大,通常选择择机方式,具体自我考量)

八、内存堆中的弱引用

当应用程序正在执行使用的对象,GC是不可能回收的,那么,就认为应用程序对该对象具有强引用。

强引用:应用程序正在使用的对象实例,不能被GC回收。

弱引用:应用程序暂时没使用的对象实例,暂时可被GC定义为可回收的实例,在回收之前,也可被应用程序再次使用后变为强引用。

假设一个对象实例被GC清理后,后续又被再次用到的场景,就会重新创建对象实例,那如果这个对象实例又比较大,这样的频繁创建... ...

当然还有优化的空间,所以,弱引用优化了以上场景。

弱引用的优点:对于频繁创建的大实例,弱类型可以做到一次创建多次使用,避免大对象实例多次创建的性能消耗。

(对于小对象使用弱类型,所带来的对对象管理上的性能消耗,是否值得)

若要对某对象建立弱引用,使用要跟踪的对象实例创建 WeakReference。 然后将 Target 属性设置为该对象,将该对象的原始引用设置为 null。(参考官方文档)

也就是说:我们可以自定义控制哪些对象实例要不要暂时不被GC垃圾回收。

九、多应用共享内存时的垃圾回收

当多个应用程序在一台主机同时运行时,对内存空间大小的分配,建议是灵活可变的,以达到各应用程序对内存利用的平衡及稳定性。

如果启用 gcTrimCommitOnLowMemory 设置,垃圾回收器会计算系统内存负载,并在负载达到 90% 时进入修整模式。除非负载下降到不到 85%,否则会一直处于修整模式。

如果条件允许,垃圾回收器可以决定 gcTrimCommitOnLowMemory 设置对当前应用没有帮助并忽略它。

如下启用 gcTrimCommitOnLowMemory 设置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <runtime>
        <gcTrimCommitOnLowMemory enabled="true"/>
    </runtime>
</configuration>

到此这篇关于.Net的GC垃圾回收原理及实现的文章就介绍到这了,更多相关.Net GC垃圾回收 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • .NET垃圾回收器(GC)原理浅析

    作为.NET进阶内容的一部分,垃圾回收器(简称GC)是必须了解的内容.本着"通俗易懂"的原则,本文将解释CLR中垃圾回收器的工作原理. 基础知识 托管堆(Managed Heap) 先来看MSDN的解释:初始化新进程时,运行时会为进程保留一个连续的地址空间区域.这个保留的地址空间被称为托管堆. "托管堆也是堆",为什么这样说呢?这么说是希望大家不要被"术语"迷惑,这个知识点的前提是"值类型和引用类型的区别".这里假设读者已经知

  • .Net的GC垃圾回收原理及实现

    一.先了解下必备的知识前提 内存中的托管与非托管,可简单理解为: 托管:可借助GC从内存中释放的数据对象(以下要描述的内容点) 非托管:必须手工借助Dispose释放资源(实现自IDisposable)的对象 内存中有栈和堆的概念区分,仅简单说明: 栈:先进后出 的特点(这里不再详细阐述) 堆:存放数据对象实例的内存空间(以下要描述的内容点) 二..Net GC的简单描述 GC垃圾回收是对于内存堆的处理过程. 当一个应用程序进程创建时,会为此应用程序在物理内存堆中分配一块虚拟的连续性内存空间,以

  • GC参考手册二java中垃圾回收原理解析

    内存碎片整理 每次执行清除(sweeping), JVM 都必须保证不可达对象占用的内存能被回收重用.但这(最终)有可能会产生内存碎片(类似于磁盘碎片), 进而引发两个问题: 写入操作越来越耗时, 因为寻找一块足够大的空闲内存会变得非常麻烦. 在创建新对象时, JVM在连续的块中分配内存.如果碎片问题很严重, 直至没有空闲片段能存放下新创建的对象,就会发生内存分配错误(allocation error). 要避免这类问题,JVM 必须确保碎片问题不失控.因此在垃圾收集过程中, 不仅仅是标记和清除

  • Go语言七篇入门教程七GC垃圾回收三色标记

    目录 GC 如何判断一个对象是否可达 三色标记法 原理如下 GC GC全称Garbage Collection 目前主流的垃圾回收算法有两类,分别是追踪式垃圾回收算法(Tracing garbage collection)和引用计数法( Reference counting ). 而三色标记法是属于追踪式垃圾回收算法的一种. 追踪式算法的核心思想是判断一个对象是否可达,因为一旦这个对象不可达就可以立刻被 GC 回收了. 如何判断一个对象是否可达 分为两步: 第一步找出所有的全局变量和当前函数栈里

  • java垃圾回收原理之GC算法基础

    正文: 相关术语翻译说明: Mark,标记; Sweep,清除; Compact,整理; 也有人翻译为压缩,译者认为GC时不存在压缩这回事. Copy,复制; copy 用作名词时一般翻译为拷贝/副本,用作动词时翻译为复制. 注: <垃圾回收算法手册>将 Mark and Sweep 翻译为: 标记-清扫算法; 译者认为 标记-清除 更容易理解. 本章简要介绍GC的基本原理和相关技术, 下一章节再详细讲解GC算法的具体实现.各种垃圾收集器的实现细节虽然并不相同,但总体而言,垃圾收集器都专注于两

  • JVM垃圾回收原理解析

    概述 Java运行时区域中,程序计数器,虚拟机栈,本地方法栈三个区域随着线程的而生,随线程而死,这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收问题.而Java堆和方法区则不一样,一个接口的多个实现类需要的内存不一样,一个方法的多个分支需要的内存可能也不一眼,我们只有在运行期,才能知道会创建的对象,这部分的内存分配和回收,是垃圾回收器所关注的.垃圾回收器需要完成三个问题:那些内存需要回收:什么时候回收以及如何回收. 那些垃圾需要回收 垃圾回收的基本思想是考察一个对象的可达性,即从根节点

  • 从JVM的内存管理角度分析Java的GC垃圾回收机制

    一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,因为有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率 ,才能提高整个应用程序的性能.本篇文章首先简单介绍GC的工作原理之后,然后再对GC的几个关键问题进行深入探讨,最后提出一些Java程序设计建议,从GC角度提高Java程序的性能.     GC的基本原理     Java的内存管理实际上就是对象的管理,其中包括对象的分配和释放.     对于程序员来说,分配对象使用

  • 图解Golang的GC垃圾回收算法

    虽然Golang的GC自打一开始,就被人所诟病,但是经过这么多年的发展,Golang的GC已经改善了非常多,变得非常优秀了. 以下是Golang GC算法的里程碑: v1.1 STW v1.3 Mark STW, Sweep 并行 v1.5 三色标记法 v1.8 hybrid write barrier 经典的GC算法有三种: 引用计数(reference counting) . 标记-清扫(mark & sweep) . 复制收集(Copy and Collection) . Golang的G

  • c#如何用好垃圾回收机制GC

    一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般有如下几种: 1.手动管理:C,C++ 2.计数管理:COM 3.自动管理:.NET,Java,PHP,GO- 但是,手动管理和计数管理的复杂性很容易产生以下典型问题: 1.程序员忘记去释放内存 2.应用程序访问已经释放的内存 产生的后果很严重,常见的如内存泄露.数据内容乱码,而且大部分时候,程序的

  • PHP垃圾回收机制简单说明

    虽然自己也是PHP的学习者,但之前还真没怎么了解PHP内部的垃圾回收流程,只是在我们的代码中用了unset,null,mysql_close,__destruct等等一些函数去释放对象防止内存溢出而已,所以上网GG下,找到了以下一些说明,作下记录"PHP可以自动进行内存管理,清除不再需要的对象.PHP使用了引用计数(reference counting)这种单纯的垃圾回收(garbage collection)机制.每个对象都内含一个引用计数器,每个reference连接到对象,计数器加1.当r

  • Java垃圾回收机制简述

    说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来.在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理. 顾名思义,垃圾回收就是释放垃圾占用的空间,那么在Java中,什么样的对象会被认定为"垃圾"?那么当一些对象被确定为垃圾之后,采用什么样的策略来进行回收(释放空间)?在目前的商业虚拟机中,有哪些典型的垃圾收集器?下面我们就来逐一探讨这些问题.以下是本文的目录大纲: 如何确定某个对象是"

随机推荐