引言

GC 作为CLR的垃圾回收器,让程序员可以把更多的关注度放在业务上而不是垃圾回收(内存回收)上。其实很多语言也有类似的东东,

如Java也有JIT 等等

GC基本概念

  • 垃圾回收机制的算法有好多种,GC为Mark-Sweep算法。
  • GC中分为三代,来优化管理不同生命周期的对象。
  • 大部分的对象在Gen0就死掉了。
  • Gen0 和Gen 1 又叫作ephemeral generations (短命代,个人翻译意见 )
  • 大于85,000bytes的对象会被直接分配到Large object heap上,且在Gen2回收时才会被回收。

GC回收时机

  1. 系统内存不足
  2. Gen0 没有足够的空间需要申请新的空间(应该是segment)
  3. 手动条用GC.Collect()

GC步骤

当进行一次垃圾回收操作时,会分三个步骤进行:
1. 先假设所有对象都是垃圾;
2. 标记出正在使用的对象; (会先找GC Roots,然后遍历GC Heap上的每个对象,生成一个对象List)
标记依据:
     a. 被变量引用的对象,仍然在作用域中。
     比如某个类中的某个方法,方法执行了一半,如果此时发生垃圾回收,那么方法块中的变量都在作用域中,那么它们都会被标记为正在使用。
     b. 被另一个对象引用的对象,仍在使用中。
3. 压缩:释放第二步中未标记的对象(不再使用,即“垃圾”)并将使用中的对象转移到连续的内存块中。
只要垃圾回收器释放了能释放的对象,它就会压缩剩余的对象,把它们都移回堆的端部,再一次形成一个连续的块。(这里其实有个更新引用或者说指针的操作)

GC处理Finalizalbe对象工作原理

上图假设是新创建对象为Gen0 代的且为Finalizable的对象,首次就会被回收(如局部的且<85,000bytes的对象)。

实现 Finalize 方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。用 Finalize 方法回收对象使用的内存需要至少两次垃圾回收。当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。这时,它不能回收具有终结器的不可访问对象。它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。该列表中的项指向托管堆中准备被调用其终止代码的对象。垃圾回收器为此列表中的对象调用 Finalize 方法,然后,将这些项从列表中移除。后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。在后来的垃圾回收中,实际上回收了对象的内存。

GC分类

从工作模式角度来看:

两大类:WorkStation GC Server GC

分类依据:

WorkStation GC 是默认的工作方式,如果你是单处理器的机器,那么这是你唯一的选择,并且及时你配置了Concurrent选项为True,也不会生效。

Server GC 在多处理器的机器上才会出现,且默认出现在Aps.net寄存服务中。他会为每个处理器都创建一个GC Heap,并且会并行执行回收操作。该模式的GC可以最大化吞吐量和较好的收缩性(4处理器+)

<configuration>
  <runtime>
    <gcServer enabled="true" />
  </runtime>
</configuration>

可以通过以上配置方式或者通过native code 类指定GC 工作模式

HRESULT CorBindToRuntimeEx( LPWSTR pwszVersion,
  LPWSTR pwszBuildFlavor, // use “svr” for server mode,
  // “wks” or NULL for workstation
  DWORD flags,
  REFCLSID rclsid,
  REFIID riid,
  LPVOID* ppv );

下表为GC为GC heap向系统申请时的基本单位Segment的默认值,注意是默认值,这些值会随着程序的实际执行情况,GC动态调整。这里了解下即可,另外正是由于有segment的概念所以回出现内存碎片的问题,所以GC在垃圾回收过程中会进行内存整理,以减少内存碎片,提高内存使用率。

 

32-bit

64-bit

Workstation GC

16 MB

256 MB

Server GC

64 MB

4 GB

Server GC with > 4 logical CPUs

32 MB

2 GB

Server GC with > 8 logical CPUs

16 MB

1 GB

从工作方式,工作侧重点和实现上来看:

两类:Foreground GC,Concurrent GC | BackGround GC(侧重于Gen2 GC性能优化,正常情况Gen0 ,Gen1的速度都比较快)

Foreground GC工作的时候绝对是.net 程序要向系统申请分配Gc Heap空间啦,所以它的优先级最高。一旦它运行,其他所有线程都会被挂起来。

通过配置文件开启或者关闭并发和后台模式,(同一个配置项)

<configuration>
<runtime>
   <gcConcurrent enabled="false" />
</runtime>
</configuration

In workstation or server garbage collection, you can enable concurrent garbage collection , which enables threads to run concurrently with a dedicated thread that performs the garbage collection for most of the duration of the collection. This option affects only garbage collections in generation 2; generations 0 and 1 are always non-concurrent because they finish very fast.


Server GC 和Workstation GC都可以开启并发GC。在GC回收的过程中大部分时间用户线程可以并发运行。但这中效果只能影响到2带GC的过程,因为0代1代的时间太短了。

  Concurrent WS Non-Concurrent WS BackGround WS
(替代并发)
Server GC Server GC Background(替代并发)
出现时间 .net 1+ .net 1+<x<.net.4 .net 4+ .net 1+ .net 4.5.1+
设计目标 在吞吐量和界面相应速度上寻找平衡点 最大化吞吐量 在WS的设计基础上,优化gen2 GC性能 多处理器机器上使用多线程处理相同类型的请求以便最大化服务程序吞吐量 优化gen2 GC性能
GC Heap数量 1 1 1 1 per processor (HT aware) 1 per processor (HT aware)
GC threads 分配空间的线程会触发GC, 分配空间的线程会触发GC线程   每个处理器都有一个专职的GC线程 每个处理器都有一个专职的GC background线程
GC线程优先权 和工作线程具有相同的优先权 和工作线程具有相同的优先权 background GC线程与工作线程有相同优先级,但都低于前台GC线程 THREAD_PRIORITY_HIGHEST background GC线程与工作线程有相同优先级,但都低于前台GC线程
工作线程(非GC线程) GC工作过程中短暂多次挂起 GC工作过程中一直被挂起 GC工作过程中短暂多次挂起,较并发性能更加(针对Gen2的) GC工作过程中会被挂起 GC工作过程中短暂多次挂起,较并发性能更加(针对Gen2的)
ephemeral generation 的前台GC工作时会挂起其他所有线程
配置方式 <gcConcurrent enabled="true"> <gcConcurrent enabled="false"> <gcConcurrent enabled="false"> <gcServer enabled="true"> <gcConcurrent enabled="false">
是否会超时       不会

----------------------------------------------------------------------------------------------

Workstation GC

-------------------------------------------------------------------------------------------------

Server garbage collection

-------------------------------------------------------------------------------------------------


Concurrent garbage collection

-------------------------------------------------------------------------------------------------

Background workstation garbage collection

-------------------------------------------------------------------------------------------------

Background server garbage collection

-------------------------------------------------------------------------------------------------

其他相关

编程的内存模型中我们会接触到“堆”和“栈”两个部分。每个线程都有自己的栈,但共享堆(当然不是直接跨线程访问的意思,只能理解为共存在堆上)。

性能计数

What is the cost of a garbage collection? How can I keep this cost at a minimum?

You can measure the GC cost for your application with a few different counters. Remember that all of these counters are updated at the end of a collection which means that if you use averages they may not be valid after a long time of inactivity.

.NET CLR Memory\% time in GC - This counter measures the amount of CPU time you spend in GC and it is calculated as (CPU time for GC/CPU time since last GC)

.NET CLR Memory\# Induced GC – This is the number of garbage collections that have occurred as a result of someone calling GC.Collect(). Ideally this should be 0 since inducing full collections means that you spend more time in the GC, and also because the GC continuously adapts itself to the allocation patterns in the application, and performing manual GCs skews this optimization.

.NET CLR Memory\# Gen X collections – This counter displays the amount of collections that have been performed for a given generation. Since the cost of gen 2 collections is high compared to Gen 1 and Gen 0 you want to have as few Gen 2 collections per Gen 1 and Gen 0 collections as possible. A ratio of 1:10:100 is pretty good.

The most common causes for high CPU in GC or a high number of Gen 2 collections compared to 1 and 0 is high allocation of large objects and letting objects survive multiple generations because of improper use of finalizers or because finalizable objects are not disposed of correctly in the application.

参考

Finding garbage

.NET垃圾回收 – 原理浅析

How does the GC work and what are the sizes of the different generations?

垃圾回收

C#技术漫谈之垃圾回收机制(GC)

托管堆与垃圾收集

关于CLR内存管理一些深层次的讨论

http://blogs.msdn.com/maoni/archive/2004/06/15/156626.aspx

http://blogs.msdn.com/maoni/archive/2004/09/25/234273.aspx

垃圾回收翻译系列(√)

不得不知的CLR中的GC的更多相关文章

  1. 在 C# CLR 中学习 C++ 之了解 extern

    一:背景 在 CLR 源码中有很多的 extern 和 extern "C" 这样的关键词,比如下面这些代码: extern size_t gc_global_mechanisms ...

  2. CLR中的程序集加载

    CLR中的程序集加载 本次来讨论一下基于.net平台的CLR中的程序集加载的机制: [注:由于.net已经开源,可利用vs2015查看c#源码的具体实现] 在运行时,JIT编译器利用程序集的TypeR ...

  3. CLR中的垃圾回收机制

    CLR中采用代(generation)来作为其垃圾回收的一种机制,其唯一的目的是提升程序的性能.基予代的垃圾回收器有以下假设: ·对象越新,其生存周期越短. ·对象越老,其生存周期越长. ·回收堆的一 ...

  4. Unity中的GC以及优化

    [简介] 常见的 Unity GC 知识点总结出来的思维导图 Unity 官方文档,正巧在博客园发现了已经有位大神(zblade)把原文翻译出来了,而且质量很高~,译文地址 在这里.下面我就可耻地把译 ...

  5. 浅谈Unity中的GC以及优化

    介绍: 在游戏运行的时候,数据主要存储在内存中,当游戏的数据不在需要的时候,存储当前数据的内存就可以被回收再次使用.内存垃圾是指当前废弃数据所占用的内存,垃圾回收(GC)是指将废弃的内存重新回收再次使 ...

  6. [C#] 类型学习笔记一:CLR中的类型,装箱和拆箱

    在学习.NET的时候,因为一些疑问,让我打算把.NET的类型篇做一个总结.总结以三篇博文的形式呈现. 这篇博文,作为三篇博文的第一篇,主要探讨了.NET Framework中的基本类型,以及这些类型一 ...

  7. 警惕C#事件使用过程中的GC陷阱

    关于C#中的事件,园里已经有大量的文章对其内在实现做过剖析,如果还不甚了解的可以阅读这篇文章 通过Demo来细看C#事件的内在机制 虽然比较早,但非常清楚地展示了事件的内部机制,总结一下就是 1.事件 ...

  8. 如何诊断RAC系统中的'gc cr multi block request'?

    'gc cr multi block request' 是RAC数据库上比较常见的一种等待事件,在RAC 上进行全表扫描(Full Table Scan)或者全索引扫描(Index Fast Full ...

  9. 如何查看子线程中的GC Alloc

    1)如何查看子线程中的GC Alloc2)Build时,提示安卓NDK异常3)如何获得ParticleSystem产生的三角形数量4)关于图片通道的问题5)GPUSkinning导致模型动画不平滑 M ...

随机推荐

  1. 恢复SQL Server被误删除的数据(再扩展)

    恢复SQL Server被误删除的数据(再扩展) 大家对本人之前的文章<恢复SQL Server被误删除的数据> 反应非常热烈,但是文章里的存储过程不能实现对备份出来的日志备份里所删数据的 ...

  2. ABP文档 - Mvc 视图

    文档目录 本节内容: 简介 AbpWebViewPage 基类 简介 ABP通过nuget包Abp.Web.Mvc集成到Mvc视图里,你可以像往常那样创建常规的视图. AbpWebViewPage 基 ...

  3. 【Big Data】HADOOP集群的配置(一)

    Hadoop集群的配置(一) 摘要: hadoop集群配置系列文档,是笔者在实验室真机环境实验后整理而得.以便随后工作所需,做以知识整理,另则与博客园朋友分享实验成果,因为笔者在学习初期,也遇到不少问 ...

  4. bcp 命令实例

    set sql_flow="select Id,',',ApplierName,',',FlowStatus,',',IsApproved,',',CreateTime from *** w ...

  5. WebSocket - ( 一.概述 )

    说到 WebSocket,不得不提 HTML5,作为近年来Web技术领域最大的改进与变化,包含CSS3.离线与存储.多媒体.连接性( Connectivity )等一系列领域,而即将介绍的 WebSo ...

  6. Android Studio 编译单个module

    前期自己要把gradle环境变量配置好 在Terminal中gradle命令行编译apk 输入gradle assembleRelease 会编译全部module编译单个modulecd ./xiru ...

  7. 编译器开发系列--Ocelot语言6.静态类型检查

    关于"静态类型检查",想必使用C 或Java 的各位应该非常熟悉了.在此过程中将检查表达式的类型,发现类型不正确的操作时就会报错.例如结构体之间无法用+ 进行加法运算,指针和数值之 ...

  8. 关于sql server 2005存储过程的写法

    打开数据库的SQL Server Managerment Studio---->数据库----->打开数据库会看见"可编程行"------->打开有存储过程--- ...

  9. ReactNative入门 —— 动画篇(下)

    在上篇动画入门文章中我们了解了在 React Native 中简单的动画的实现方式,本篇将作为上篇的延续,介绍如何使用 Animated 实现一些比较复杂的动画. 动画组合 在 Animated 中提 ...

  10. 使用Masstransit开发基于消息传递的分布式应用

    Masstransit作为.Net平台下的一款优秀的开源产品却没有得到应有的关注,这段时间有机会阅读了Masstransit的源码,我觉得我有必要普及一下这个框架的使用. 值得一提的是Masstran ...