您的位置:首页 > 其它

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

2009-09-14 18:31 483 查看
继续接着上篇的分析,

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主要在以下三种情况下使用:

线程希望增加CPU分给这个线程的使用时间的时候。

线程在需要分配一大块内存区域的时候。

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 (unsignedint gen, BOOL collect_classes_p)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: