kvm垃圾收集-002

本文我們來介紹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;
}

其中參數爲垃圾收集後所期望的可用內存大小.

步驟如下:

  1. 如果gcInProgress 不等於0,就意味着當前正在gc中,如果循環調用gc是不允許的.並修改gc標記位.
  2. 等待異步線程執行完畢
  3. 在gc前 保存執行環境
  4. 執行gc,關於此處,下文介紹
  5. 在gc執行後,恢復執行環境
  6. 重新啓動異步線程
  7. 重置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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章