本文我们来介绍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;
}