本文介绍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等方法我们后续文章介绍…(这几个方法还是比较复杂的,就不在这里展开了)