本文介紹kvm中垃圾收集中的sweep.sweep的意思是: 將垃圾對象清除(其實垃圾區域的對象還是存在的,但是由於沒有對象引用,同時之後在分配對象時,會在這些區域分配,分配時會進行清零操作.因此,也就表現爲實際清除了一樣)。此處的代碼如下:
static CHUNK
sweepTheHeap(long *maximumFreeSizeP)
{
CHUNK firstFreeChunk = NULL;
CHUNK newChunk;
CHUNK* nextChunkPtr = &firstFreeChunk;
bool_t done = FALSE;
cell* scanner = CurrentHeap; /* current object */
cell* endScanPoint = CurrentHeapEnd;
long maximumFreeSize = 0;
long thisFreeSize;
do {
/* Skip over groups of live objects 1. 跳過存活的對象 */
cell *lastLive;
while (scanner < endScanPoint && ISKEPT(*scanner)) {
*scanner &= ~MARKBIT; // 將標記位置0
scanner += SIZE(*scanner) + HEADERSIZE;
}
lastLive = scanner;
/* Skip over all the subsequent dead objects 2. 跳過所有的垃圾對象*/
while (scanner < endScanPoint && !ISKEPT(*scanner)) {
#if INCLUDEDEBUGCODE
if (tracememoryallocation && (TYPE(*scanner) != GCT_FREE)) {
Log->freeObject((long)scanner,
(INSTANCE_CLASS)((OBJECT)(scanner + HEADERSIZE))->ofClass,
(long)SIZE(*scanner) + HEADERSIZE);
}
#endif /* INCLUDEDEBUGCODE */
scanner += SIZE(*scanner) + HEADERSIZE;
}
if (scanner == endScanPoint) {
if (scanner == lastLive) {
/* The memory ended precisely with a live object. 此時的情況是 內存中都是存活對象 */
break;
} else {
done = TRUE;
}
}
// 計算free 的大小
thisFreeSize = (scanner - lastLive - 1);
newChunk = (CHUNK)lastLive;
newChunk->size = thisFreeSize << TYPEBITS;
*nextChunkPtr = newChunk;
nextChunkPtr = &newChunk->next;
if (thisFreeSize > maximumFreeSize) {
maximumFreeSize = thisFreeSize;
}
} while (!done);
*nextChunkPtr = NULL;
*maximumFreeSizeP = maximumFreeSize;
return firstFreeChunk;
}
此處的代碼比較簡單.將垃圾對象所在的區域當做free 區.同時構建成free鏈表.另外此處還將存活對象的標記位置爲0(以備下次gc時使用).
當sweep後,代碼回到garbageCollectForReal方法.其代碼如下:
firstFreeChunk = sweepTheHeap(&maximumFreeSize);
#if ENABLE_HEAP_COMPACTION
if (realSize > maximumFreeSize) {// 當heap 內最大的可用內存不滿足要求時,需要進行壓縮處理
/* We need to compact the heap. */
breakTableStruct currentTable;
// 壓縮
cell* freeStart = compactTheHeap(¤tTable, firstFreeChunk);
if (currentTable.length > 0) {
// 修改指針
updateRootObjects(¤tTable);
updateHeapObjects(¤tTable, freeStart);
}
// 壓縮後,重新計算free 的大小.整理後, free 只有一塊.
if (freeStart < CurrentHeapEnd - 1) {
firstFreeChunk = (CHUNK)freeStart;
firstFreeChunk->size =
(CurrentHeapEnd - freeStart - HEADERSIZE) << TYPEBITS;
firstFreeChunk->next = NULL;
} else {
/*
* 沒有空閒內存
*/
firstFreeChunk = NULL;
}
}
#endif
FirstFreeChunk = firstFreeChunk;
此時,如果sweep後最大的free chunk的大小不滿足要求(realSize).則需要進行壓縮.也就是將活動對象移動到一端.同時在移動的過程中要更新對象的引用(因爲對象的位置變了)。同時, free chunk也就只有一個了(壓縮的本來含義).
關於壓縮的compactTheHeap, updateRootObjects等方法我們後續文章介紹…(這幾個方法還是比較複雜的,就不在這裏展開了)