SSCLI中GC垃圾回收源码分析(2) - GarbageCollect()与Spin Lock

继续接着上篇的分析,

F11从Fcall中跳出来,就到了sscli20/clr/src/vm/gcsmp.cpp中关于Garbage Collect的最外部的方法GCHeap::GarbageCollect:

HRESULT
GCHeap::GarbageCollect (int generation, BOOL collect_classes_p)
{

    UINT GenerationAtEntry = GcCount;
    //This loop is necessary for concurrent GC because
    //during concurrent GC we get in and out of
    //GarbageCollectGeneration without doing an independent GC
    do
    {
        enter_spin_lock (&gc_heap::more_space_lock);

        COUNTER_ONLY(GetPrivatePerfCounters().m_GC.cInducedGCs ++);

        int gen = (generation < 0) ? max_generation :
            min (generation, max_generation);
        GarbageCollectGeneration (gen, collect_classes_p);

        leave_spin_lock (&gc_heap::more_space_lock);

    }
    while (GenerationAtEntry == GcCount);
    return S_OK;
}

这里使用一个do-While循环的主要目的,是由于在并发GC的时候,需要在不同的时间进进出出地调用GarbageCollectGeneration方法。而在一个非并发独立的GC中,则不需要这种循环。

在enter_spin_lock和leave_spin_lock成对使用,这两句的主要功能,就是访问位于sscli20/clr/src/vm/gcsmppriv.h的GC Heap中定义的一个Spin Lock:

GCSpinLock more_space_lock; //lock while allocating more space

more_space_lock主要在以下三种情况下使用:

  1. 线程希望增加CPU分给这个线程的使用时间的时候。
  2. 线程在需要分配一大块内存区域的时候。
  3. GarbageCollect在实现的时候,实际调用的是GarbageCollectGeneration方法,使用more_space_lock来阻止GarbageCollect之后程序直接调用GarbageCollectGeneration方法进行GC。

关于Spinlock的读写在SSCLI中的实现,可以在sscli20/clr/src/vm/gcsmp.cpp中找到:

inline
static void enter_spin_lock (LONG volatile * lock)
{
retry:

    if (FastInterlockExchange (lock, 0) >= 0)
    {
        unsigned int i = 0;
        while (*lock >= 0)
        {
            if (++i & 7)
                __SwitchToThread (0);
            else
            {
                WaitLonger(i);
            }
        }
        goto retry;
    }
}

这里, FastInterlockExchange是比较有意思的。Spinlock的实现,是一个thread对一个flag标志位通过死循环来不停的查询,直到这个Flag可用为止。出于效率和安全性的多方面因素的考虑,因为一个object是否可以使用,是在object的synblock里面有一个bit位来标识spinlock的,因此这个地方的FastInterlockExchange的实现,是直接使用汇编代码来高效的实现,可以在sscli20/clr/src/vm/i386/asmhelpers.asm文件中找到:

FASTCALL_FUNC ExchangeMP,8
        _ASSERT_ALIGNED_4_X86 ecx
        mov     eax, [ecx]      ; attempted comparand
retryMP:
  lock  cmpxchg [ecx], edx
        jne     retry1MP        ; predicted NOT taken
        retn
retry1MP:
        jmp     retryMP
FASTCALL_ENDFUNC ExchangeMP

对Spinlock的访问就使用上面的代码来一直读,读到相等就执行retn来退出,否则一直重复执行 cmpxchg指令来进行比较。

在得到lock之后,就到了GC的主要实现部分,位于sscli20/clr/src/vm/gcsmp.cpp中的GCHeap::GarbageCollectGeneration (unsigned int gen, BOOL collect_classes_p)。

源码简介:Microsoft 发布了 sscli 2.0,所谓的 sscli 就是 Shared Source CLI。基本上是 .NET Framework 2.0 的 Microsoft 实现,当然是实际发布的 .NET Framework 2.0 的一个简化版本。 sscli 2.0 中包含很多有趣的东西,包括: 01、vm - 包含了 CLI 核心实现,包括垃圾收集器、类装入器、类型系统、错误报告系统、应用程序域、配件、代理支持、反射、安全性和代码管理器。 02、csharp - 包含了使用 C++ 编写的 C# 编译器(csc.exe)和配件连接器。 03、classlibnative - 包含了公共类型和国际化例程。 04、ipcman - 包含跨进程通讯系统的源代码。 05、managedlibraries - 包含Remoting 和 SoapSerializer 的源代码。 06、utilcode - 包含被运行时、工具和 C# 编译器使用的核心例程,例如路径处理和分析、数组和散列表管理、C 运行库、字符大小写支持、库和配件载入、调试和日志支持、同步机制,还包括字符串格式化、GUID创建、错误处理、注册表以及配置访问等。 07、md - 包含元数据的读取器和编写器。 08、fjit - 包含 sscli JIT 编译器和验证器。 09、fusion - 包含配件绑定、策略检查和全局配件缓存的实现代码。 10、bcl - 包含 ECMA 基础类库的 C# 代码,包括大部分 System 名字空间下的代码。 11、debug - 包含运行时调试器的源代码。 12、ilasm - 包含 CIL 汇编器的源代码。 13、ildasm - 包含 CIL 反汇编器的源代码。 14、tools - 包含 PEVerify、clix.exe、metainfo.exe、托管调试器符号的读写器以及其它工具的源代码。 15、toolbox - 包含 caspol、strike 等其它工具的源代码。 16、dlls - 包含在构建过程中所需要的本机共享库。 17、xmlparser - 包含 XML 分析器的源代码。 18、fx - 包含主要名字空间中类的实现,包括正则表达式、XML和网络等。 19、jscript - 包含了使用 C# 编写的 JScript 编译器。 20、pal - 包含了平台适配层(PAL)的实现,包括 unix 和 win32 两个平台。 21、palrt - 包含 PAL 运行时的实现。 22、samples - 示例。 23、tests - 大量的测试用例和套件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值