CLR的核心功能之一就是垃圾回收(garbage collection),关于GC的基本概念本文不在赘述。这里主要针对GC的两种工作模式展开讨论和研究。
该模式设计的目的是用于客户端类的应用(Client),这类应用的部署特点是同一台机器会部署很多应用程序,并且这些应用程序的性能要求并没有服务器程序(nginx、asp.net等)那么高。那么在此种场景下,GC做了哪些设计和调整呢?
顾名思义,Server模式就是针对服务器场景设计的,此类应用的部署特点是服务器内存大CPU核心多,部署的程序数量少(基本都是专机专用),但是对程序性能要求非常高。于是这种模式下,GC的也做了相应的调整:

注意上表的值是每个堆的大小,对多核CPU来说,Server模式的GC堆分配空间显然是大于Wordstation模式的。
我们知道CLR根据GC次数把对象分为0代、1代、2代。其中01代执行的频率高、耗时短,也被称为ephemeral generations。 根据CLR的设计,执行01代垃圾回收时,所有托管线程是被短暂挂起,直到垃圾回收结束后再恢复执行。但是执行2代的垃圾回收会耗时相对更长,如果也挂起全部线程,无疑会对程序响应造成较大的影响。
因此CLR提出单独分配专用线程,用来执行2代垃圾回收,且此线程执行时不会挂起其它线程,从而降低对程序的影响。注意此处2代垃圾回收其实是包含了之前的01代的,只不过01代执行很短暂且01代执行时会依旧会挂起全部线程。
关于Background专用线程的数量,workstation模式拥有1个专用线程,server模式分配和逻辑处理器数量一致的专用线程。
在workstation模式下background回收的执行示意图:

上图的解读:
在server模式下background回收的执行示意图:

上图解读:
需要额外说明是,background是最新的叫法,之前版本称为concurrent。他们之间的升级关系如下:
| workstation模式 | server模式 | |
| .NET Framework 4之前 | concurrent gc | 不支持 |
| .NET Framework 4 | background gc | 不支持 |
| .NET Framework 4.5及之后 | background gc | background gc |
| workstation模式 | server模式 | 说明 | |
| 专用线程 | 无 | 有单独的专用线程,且数量等于CPU核心数 | server模式充分利用多核特性,最大化保证快速完成GC操作。 |
| gc执行的优先级 | 普通 | THREAD_PRIORITY_HIGHEST | workstation模式线程执行GC操作需要和普通业务线程平等竞争CPU,GC不能最快的完成。 |
| gc堆数量 | 1 | 多个,数量等于CPU核心数 | workstation模式堆数量少且内存更少,但是容易引起GC。 server模式堆数量多占用内存更多,可以降低触发GC的次数,进而提高程序的响应性能。 |
| background支持情况 | 支持,但只会分配1个background专用线程 | 支持,分配的background专用线程数量等于CPU核心数 |
|
项目文件csproj中设置:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <ServerGarbageCollection>true</ServerGarbageCollection> <ConcurrentGarbageCollection>true</ConcurrentGarbageCollection> </PropertyGroup></Project>runtimeconfig.json 文件设置:
{ "runtimeOptions":{ "configProperties":{ "System.GC.Server":true, "System.GC.Concurrent":true } }}单独说明一点,对于单核CPU的计算机,无论如何配置都是workstation模式,当然现代计算机这种情况极少了。
对于workstation模式的程序进程,通过dump查看gc堆信息和gc模式信息分别如下:
0:004> !eeversion6.0.21.52210 freeWorkstation modeSOS Version: 6.0.5.7301 retail build0:004> !eeheap -gcNumber of GC Heaps: 1generation 0 starts at 0x0000024E80001030generation 1 starts at 0x0000024E80001018generation 2 starts at 0x0000024E80001000ephemeral segment allocation context: none segment begin allocated committed allocated size committed size0000024E80000000 0000024E80001000 0000024E8010DFE8 0000024E80112000 0x10cfe8(1101800) 0x111000(1118208)Large object heap starts at 0x0000024E90001000 segment begin allocated committed allocated size committed size0000024E90000000 0000024E90001000 0000024E9004FD40 0000024E90050000 0x4ed40(322880) 0x4f000(323584)Pinned object heap starts at 0x0000024E980010000000024E98000000 0000024E98001000 0000024E98006C50 0000024E98012000 0x5c50(23632) 0x11000(69632)Total Allocated Size: Size: 0x161978 (1448312) bytes.Total Committed Size: Size: 0x160000 (1441792) bytes.------------------------------GC Allocated Heap Size: Size: 0x161978 (1448312) bytes.GC Committed Heap Size: Size: 0x160000 (1441792) bytes.对于server模式的程序进程,通过dump查看gc堆信息和gc模式信息分别如下:
0:012> !eeversion6.0.21.52210 freeServer mode with 8 gc heapsSOS Version: 6.0.5.7301 retail build0:015> !eeheap -gcNumber of GC Heaps: 8------------------------------Heap 0 (000001E88D3F3AD0)generation 0 starts at 0x000001E88EF51030generation 1 starts at 0x000001E88EF51018generation 2 starts at 0x000001E88EF51000ephemeral segment allocation context: none segment begin allocated committed allocated size committed size000001E88EF50000 000001E88EF51000 000001E88EF51048 000001E88EF52000 0x48(72) 0x1000(4096)Large object heap starts at 0x000001EC8EF51000 segment begin allocated committed allocated size committed size000001EC8EF50000 000001EC8EF51000 000001EC8EF51018 000001EC8EF52000 0x18(24) 0x1000(4096)Pinned object heap starts at 0x000001ED0EF51000000001ED0EF50000 000001ED0EF51000 000001ED0EF53010 000001ED0EF62000 0x2010(8208) 0x11000(69632)Allocated Heap Size: Size: 0x2070 (8304) bytes.Committed Heap Size: Size: 0x2000 (8192) bytes.------------------------------Heap 1 (000001E88D41F830)generation 0 starts at 0x000001E90EF51030generation 1 starts at 0x000001E90EF51018generation 2 starts at 0x000001E90EF51000ephemeral segment allocation context: none segment begin allocated committed allocated size committed size000001E90EF50000 000001E90EF51000 000001E90EF51048 000001E90EF52000 0x48(72) 0x1000(4096)Large object heap starts at 0x000001EC9EF51000 segment begin allocated committed allocated size committed size000001EC9EF50000 000001EC9EF51000 000001EC9EF51018 000001EC9EF52000 0x18(24) 0x1000(4096)Pinned object heap starts at 0x000001ED1EF51000000001ED1EF50000 000001ED1EF51000 000001ED1EF51018 000001ED1EF52000 0x18(24) 0x1000(4096)Allocated Heap Size: Size: 0x78 (120) bytes.Committed Heap Size: Size: 0x2000 (8192) bytes.------------------------------Heap 2 (000001E88D426EE0)generation 0 starts at 0x000001E98EF51030generation 1 starts at 0x000001E98EF51018generation 2 starts at 0x000001E98EF51000ephemeral segment allocation context: none segment begin allocated committed allocated size committed size000001E98EF50000 000001E98EF51000 000001E98EF51048 000001E98EF52000 0x48(72) 0x1000(4096)Large object heap starts at 0x000001ECAEF51000 segment begin allocated committed allocated size committed size000001ECAEF50000 000001ECAEF51000 000001ECAEF51018 000001ECAEF52000 0x18(24) 0x1000(4096)Pinned object heap starts at 0x000001ED2EF51000000001ED2EF50000 000001ED2EF51000 000001ED2EF51430 000001ED2EF52000 0x430(1072) 0x1000(4096)Allocated Heap Size: Size: 0x490 (1168) bytes.Committed Heap Size: Size: 0x2000 (8192) bytes.------------------------------Heap 3 (000001ED9B54AFB0)generation 0 starts at 0x000001EA0EF51030generation 1 starts at 0x000001EA0EF51018generation 2 starts at 0x000001EA0EF51000ephemeral segment allocation context: none segment begin allocated committed allocated size committed size000001EA0EF50000 000001EA0EF51000 000001EA0EF51048 000001EA0EF52000 0x48(72) 0x1000(4096)Large object heap starts at 0x000001ECBEF51000 segment begin allocated committed allocated size committed size000001ECBEF50000 000001ECBEF51000 000001ECBEF51018 000001ECBEF52000 0x18(24) 0x1000(4096)Pinned object heap starts at 0x000001ED3EF51000000001ED3EF50000 000001ED3EF51000 000001ED3EF51018 000001ED3EF52000 0x18(24) 0x1000(4096)Allocated Heap Size: Size: 0x78 (120) bytes.Committed Heap Size: Size: 0x2000 (8192) bytes.------------------------------Heap 4 (000001ED9B576570)generation 0 starts at 0x000001EA8EF51030generation 1 starts at 0x000001EA8EF51018generation 2 starts at 0x000001EA8EF51000ephemeral segment allocation context: none segment begin allocated committed allocated size committed size000001EA8EF50000 000001EA8EF51000 000001EA8EF51048 000001EA8EF52000 0x48(72) 0x1000(4096)Large object heap starts at 0x000001ECCEF51000 segment begin allocated committed allocated size committed size000001ECCEF50000 000001ECCEF51000 000001ECCEF51018 000001ECCEF52000 0x18(24) 0x1000(4096)Pinned object heap starts at 0x000001ED4EF51000000001ED4EF50000 000001ED4EF51000 000001ED4EF51018 000001ED4EF52000 0x18(24) 0x1000(4096)Allocated Heap Size: Size: 0x78 (120) bytes.Committed Heap Size: Size: 0x2000 (8192) bytes.------------------------------Heap 5 (000001ED9B5A2420)generation 0 starts at 0x000001EB0EF51030generation 1 starts at 0x000001EB0EF51018generation 2 starts at 0x000001EB0EF51000ephemeral segment allocation context: none segment begin allocated committed allocated size committed size000001EB0EF50000 000001EB0EF51000 000001EB0EF673D8 000001EB0EF72000 0x163d8(91096) 0x21000(135168)Large object heap starts at 0x000001ECDEF51000 segment begin allocated committed allocated size committed size000001ECDEF50000 000001ECDEF51000 000001ECDEF51018 000001ECDEF52000 0x18(24) 0x1000(4096)Pinned object heap starts at 0x000001ED5EF51000000001ED5EF50000 000001ED5EF51000 000001ED5EF53010 000001ED5EF62000 0x2010(8208) 0x11000(69632)Allocated Heap Size: Size: 0x18400 (99328) bytes.Committed Heap Size: Size: 0x22000 (139264) bytes.------------------------------Heap 6 (000001ED9B5CE2D0)generation 0 starts at 0x000001EB8EF51030generation 1 starts at 0x000001EB8EF51018generation 2 starts at 0x000001EB8EF51000ephemeral segment allocation context: none segment begin allocated committed allocated size committed size000001EB8EF50000 000001EB8EF51000 000001EB8EF51048 000001EB8EF52000 0x48(72) 0x1000(4096)Large object heap starts at 0x000001ECEEF51000 segment begin allocated committed allocated size committed size000001ECEEF50000 000001ECEEF51000 000001ECEEF51018 000001ECEEF52000 0x18(24) 0x1000(4096)Pinned object heap starts at 0x000001ED6EF51000000001ED6EF50000 000001ED6EF51000 000001ED6EF51018 000001ED6EF52000 0x18(24) 0x1000(4096)Allocated Heap Size: Size: 0x78 (120) bytes.Committed Heap Size: Size: 0x2000 (8192) bytes.------------------------------Heap 7 (000001ED9B5FA180)generation 0 starts at 0x000001EC0EF51030generation 1 starts at 0x000001EC0EF51018generation 2 starts at 0x000001EC0EF51000ephemeral segment allocation context: none segment begin allocated committed allocated size committed size000001EC0EF50000 000001EC0EF51000 000001EC0EF51048 000001EC0EF52000 0x48(72) 0x1000(4096)Large object heap starts at 0x000001ECFEF51000 segment begin allocated committed allocated size committed size000001ECFEF50000 000001ECFEF51000 000001ECFEF51018 000001ECFEF52000 0x18(24) 0x1000(4096)Pinned object heap starts at 0x000001ED7EF51000000001ED7EF50000 000001ED7EF51000 000001ED7EF51018 000001ED7EF52000 0x18(24) 0x1000(4096)Allocated Heap Size: Size: 0x78 (120) bytes.Committed Heap Size: Size: 0x2000 (8192) bytes.------------------------------GC Allocated Heap Size: Size: 0x1ab58 (109400) bytes.GC Committed Heap Size: Size: 0x30000 (196608) bytes.本文主要参阅了微软官方文档,对GC的工作模式进行了探究和验证。可以看到,微软设计这2个GC工作模式的目的是为了.net应用程序在不同场景下有好的程序表现,并没有孰优孰劣的问题。这个功能特点可以类比现在自动挡汽车的工作模式有节能模式、道路模式、雪地模式、沙漠模式一样。因此,在实际开发程序时,对普通客户端应用如winfrom一般选择workstation模式,对于服务器程序如asp.net 一般选择server模式。