in libs/base/gc.cpp [487:583]
static void sweep(int flags) {
RefBlock *prevFreePtr = NULL;
uint32_t freeSize = 0;
uint32_t totalSize = 0;
uint32_t maxFreeBlock = 0;
firstFree = NULL;
gcStats.numGC++;
for (auto h = firstBlock; h; h = h->next) {
auto d = h->data;
auto words = BYTES_TO_WORDS(h->blockSize);
auto end = d + words;
totalSize += words;
VLOG("sweep: %p - %p", d, end);
while (d < end) {
if (IS_LIVE(d->vtable)) {
VVLOG("Live %p", d);
d->setVT(d->vt() & ~MARKED_MASK);
d += getObjectSize(d);
} else {
auto start = (RefBlock *)d;
while (d < end) {
if (IS_FREE(d->vtable)) {
VVLOG("Free %p", d);
} else if (IS_LIVE(d->vtable)) {
break;
} else if (IS_ARRAY(d->vtable)) {
VVLOG("Dead Arr %p", d);
} else {
VVLOG("Dead Obj %p", d);
GC_CHECK(d->vtable->magic == VTABLE_MAGIC, 41);
d->destroyVT();
VVLOG("destroyed");
}
d += getObjectSize(d);
}
auto sz = d - (RefObject *)start;
freeSize += sz;
if (sz > (int)maxFreeBlock)
maxFreeBlock = sz;
#ifdef PXT_GC_CHECKS
memset((void *)start, 0xff, WORDS_TO_BYTES(sz));
#endif
start->setVT((sz << 2) | FREE_MASK);
if (sz > 1) {
start->nextFree = NULL;
if (!prevFreePtr) {
firstFree = start;
} else {
prevFreePtr->nextFree = start;
}
prevFreePtr = start;
}
}
}
}
if (midPtr) {
uint32_t currFree = 0;
#ifdef PXT_ESP32
auto limit = freeSize * 1 / 4;
#else
auto limit = freeSize * 1 / 2;
#endif
for (auto p = firstFree; p; p = p->nextFree) {
auto len = VAR_BLOCK_WORDS(p->vtable);
currFree += len;
if (currFree > limit) {
midPtr = (uint8_t *)p + ((limit - currFree + len) << 2);
break;
}
}
}
freeSize = WORDS_TO_BYTES(freeSize);
totalSize = WORDS_TO_BYTES(totalSize);
maxFreeBlock = WORDS_TO_BYTES(maxFreeBlock);
gcStats.lastFreeBytes = freeSize;
gcStats.lastMaxBlockBytes = maxFreeBlock;
if (gcStats.minFreeBytes == 0 || gcStats.minFreeBytes > freeSize)
gcStats.minFreeBytes = freeSize;
if (flags & 1)
DMESG("GC %d/%d free; %d maxBlock", freeSize, totalSize, maxFreeBlock);
else
LOG("GC %d/%d free; %d maxBlock", freeSize, totalSize, maxFreeBlock);
#ifndef GC_GET_HEAP_SIZE
// if the heap is 90% full, allocate a new block
if (freeSize * 10 <= totalSize) {
allocateBlock();
}
#endif
}