在前一篇中我讲解了new是怎么工作的, 但是却一笔跳过了内存分配相关的部分.
在这一篇中我将详细讲解GC内存分配器的内部实现.
在看这一篇之前请必须先看完微软BOTR文档中的"Garbage Collection Design",
原文地址是: https://github.com/dotnet/coreclr/blob/master/Documentation/botr/garbage-collection.md
译文可以看知平软件的译文或我后来的译文
请务必先看完"Garbage Collection Design", 否则以下内容你很可能会无法理解
服务器GC和工作站GC
关于服务器GC和工作站GC的区别, 网上已经有很多资料讲解这篇就不再说明了.
我们来看服务器GC和工作站GC的代码是怎么区别开来的.
默认编译CoreCLR会对同一份代码以使用服务器GC还是工作站GC的区别编译两次, 分别在SVR和WKS命名空间中:
源代码: https://github.com/dotnet/coreclr/blob/release/1.1.0/src/gc/gcsvr.cpp
#define SERVER_GC 1namespace SVR {
#include "gcimpl.h"#include "gc.cpp"}
源代码: https://github.com/dotnet/coreclr/blob/release/1.1.0/src/gc/gcwks.cpp
#ifdef SERVER_GC#undef SERVER_GC#endifnamespace WKS {
#include "gcimpl.h"#include "gc.cpp"}
当定义了SERVER_GC时, MULTIPLE_HEAPS和会被同时定义.
定义了MULTIPLE_HEAPS会使用多个堆(Heap), 服务器GC每个cpu核心都会对应一个堆(默认), 工作站GC则全局使用同一个堆.
源代码: https://github.com/dotnet/coreclr/blob/release/1.1.0/src/gc/gcimpl.h
#ifdef SERVER_GC#define MULTIPLE_HEAPS 1#endif // SERVER_GC
后台GC无论是服务器GC还是工作站GC都会默认支持, 但运行时不一定会启用.
源代码: https://github.com/dotnet/coreclr/blob/release/1.1.0/src/gc/gcpriv.h
#define BACKGROUND_GC //concurrent background GC (requires WRITE_WATCH)
我们从https://www.microsoft.com/net下回来的CoreCLR安装包中已经包含了服务器GC和后台GC的支持,但默认不会开启.
开启它们可以修改project.json中的·runtimeOptions·节, 例子如下:
{
"runtimeOptions": {
"configProperties": {
"System.GC.Server": true,
"System.GC.Concurrent": true
}
}}
设置后发布项目可以看到coreapp.runtimeconfig.json, 运行时会只看这个文件.
微软官方的文档: https://docs.microsoft.com/en-us/dotnet/articles/core/tools/project-json
GC相关的类和它们的关系
我先用两张图来解释服务器GC和工作站GC下GC相关的类的关系
图中一共有5个类型
GCHeap
-
实现了IGCHeap接口, 公开GC层的接口给EE(运行引擎)层调用
在工作站GC下只有一个实例, 不会关联gc_heap对象, 因为工作站GC下gc_heap的所有成员都会被定义为静态变量
在服务器GC下有1+cpu核心数个实例(默认), 第一个实例用于当接口, 其它对应cpu核心的实例都会各关联一个gc_heap实例
gc_heap
-
内部的使用的堆类型, 用于负责内存的分配和回收
在工作站GC下无实例, 所有成员都会定义为静态变量
在工作站GC下generation_table这个成员不会被定义, 而是使用全局变量generation_table
在服务器GC下有cpu核心数个实例(默认), 各关联一个GCHeap实例
generation
-
储存各个代的信息, 例如地址范围和使用的段
储存在generation_table中, 一个generation_table包含了5个generation, 前面的是0 1 2 3代, 最后一个不会被初始化和使用
在工作站GC下只有1个generation_table, 就是全局变量generation_table
在服务器GC下generation_table是gc_heap的成员, 有多少个gc_heap就有多少个generation_table
heap_segment
-
堆段, 供分配器使用的一段内存, 用链表形式保存
每个gc_heap中都有一个或一个以上的segment
每个gc_heap中都有一个ephemeral heap segment(用于存放最年轻对象)
每个gc_heap中都有一个large heap