本文我們來介紹kvm中的垃圾收集器的實現.其算法爲mark-and-sweep(含有壓縮功能).其方法爲garbageCollect.代碼如下:
void
garbageCollect(int moreMemory)
{
#if INCLUDEDEBUGCODE
int beforeCollection = 0;
int afterCollection = 0;
#endif
// 1. 如果gcInProgress 不等於0,就意味着當前正在gc中,如果循環調用gc是不允許的
if (gcInProgress != 0) {
fatalVMError(KVM_MSG_CIRCULAR_GC_INVOCATION);
}
// 修改gc標記位
gcInProgress++;
// 2. 等待異步線程執行完畢
RundownAsynchronousFunctions();
if (ENABLEPROFILING && INCLUDEDEBUGCODE) {
checkHeap();
}
#if INCLUDEDEBUGCODE
if ((tracegarbagecollection || tracegarbagecollectionverbose)
&& !TERSE_MESSAGES) {
Log->startGC();
}
#endif
#if INCLUDEDEBUGCODE
if (ENABLEPROFILING || tracegarbagecollection
|| tracegarbagecollectionverbose) {
beforeCollection = memoryFree();
}
#endif
MonitorCache = NULL; /* Clear any temporary monitors */
// 3. 在gc前 保存執行環境
if (CurrentThread) {
storeExecutionEnvironment(CurrentThread);
}
// 4. 執行gc
garbageCollectForReal(moreMemory);
// 5. 在gc執行後,恢復執行環境
if (CurrentThread) {
loadExecutionEnvironment(CurrentThread);
}
#if INCLUDEDEBUGCODE
if (ENABLEPROFILING || tracegarbagecollection
|| tracegarbagecollectionverbose) {
afterCollection = memoryFree();
#if ENABLEPROFILING
GarbageCollectionCounter += 1;
DynamicDeallocationCounter += (afterCollection - beforeCollection);
#endif
if (tracegarbagecollection || tracegarbagecollectionverbose) {
Log->endGC(afterCollection - beforeCollection, afterCollection, getHeapSize());
}
}
#endif /* INCLUDEDEBUGCODE */
// 6. 重新啓動異步線程
RestartAsynchronousFunctions();
// 7. 重置gc標記位
gcInProgress = 0;
}
其中參數爲垃圾收集後所期望的可用內存大小.
步驟如下:
- 如果gcInProgress 不等於0,就意味着當前正在gc中,如果循環調用gc是不允許的.並修改gc標記位.
- 等待異步線程執行完畢
- 在gc前 保存執行環境
- 執行gc,關於此處,下文介紹
- 在gc執行後,恢復執行環境
- 重新啓動異步線程
- 重置gc標記位
其中第二步代碼如下:
void RundownAsynchronousFunctions(void) {
for (;;) {
if (collectorIsRunning) {
fatalError(KVM_MSG_COLLECTOR_RUNNING_IN_RUNDOWNASYNCHRONOUSFUNCTIONS);
}
START_CRITICAL_SECTION
if (AsyncThreadCount == 0) {
collectorIsRunning = TRUE;
}
END_CRITICAL_SECTION
if (collectorIsRunning) {
break;
}
/* Wait */
Yield_md();
}
}
通過循環等待異步線程執行完畢.其中START_CRITICAL_SECTION, END_CRITICAL_SECTION爲宏.定義如下:
void enterSystemCriticalSection(void);
void exitSystemCriticalSection(void);
#define START_CRITICAL_SECTION { enterSystemCriticalSection();
#define END_CRITICAL_SECTION exitSystemCriticalSection(); }
可見,此處是線程鎖.關於這點,可以參考如下鏈接:
線程鎖的概念函數EnterCriticalSection和LeaveCriticalSection的用法
在gc前保存執行環境的代碼如下:
void storeExecutionEnvironment(THREAD thisThread)
{
// 將當前線程的執行環境(vm 所使用的寄存器)保存到THREAD中
thisThread->fpStore = getFP();
thisThread->spStore = getSP();
thisThread->ipStore = getIP();
}
與之所對應的就是恢復執行環境,其代碼如下:
void loadExecutionEnvironment(THREAD thisThread)
{
// 恢復線程執行環境
setFP(thisThread->fpStore);
setLP(FRAMELOCALS(getFP()));
setCP(getFP()->thisMethod->ofClass->constPool);
setSP(thisThread->spStore);
setIP(thisThread->ipStore);
}
重新啓動異步線程的代碼如下:
void RestartAsynchronousFunctions(void) {
if (!collectorIsRunning) {
fatalError(KVM_MSG_COLLECTOR_NOT_RUNNING_ON_ENTRY_TO_RESTARTASYNCHRONOUSFUNCTIONS);
}
collectorIsRunning = FALSE;
}