不得不知的CLR中的GC

时间:2023-12-19 08:07:43

引言

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

如Java也有JIT 等等

GC基本概念

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

不得不知的CLR中的GC

GC回收时机

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

GC步骤

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

GC处理Finalizalbe对象工作原理

不得不知的CLR中的GC

上图假设是新创建对象为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">
是否会超时       不会

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

不得不知的CLR中的GC

Workstation GC

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

不得不知的CLR中的GC

Server garbage collection

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

不得不知的CLR中的GC
Concurrent garbage collection

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

不得不知的CLR中的GC

Background workstation garbage collection

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

不得不知的CLR中的GC

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

垃圾回收翻译系列(√)