From 2affe19182b99d8d1c9655fa0c58c8af3e0b9506 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 16 May 2017 12:42:42 +0200 Subject: Free up completely empty Chunks, and return the memory to the OS Detect any Chunk that's completely empty, deallocate it and return the memory to the OS (as far as that's supported). Change-Id: I6b6a77f2cdf478cbf16aad30a9cae37c98c6500e Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 30 ++++++++++++++++++++++-------- src/qml/memory/qv4mmdefs_p.h | 6 +++++- 2 files changed, 27 insertions(+), 9 deletions(-) (limited to 'src/qml/memory') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 0a6dfb9170..ef36e62373 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -275,8 +275,9 @@ QString binary(quintptr) { return QString(); } #define SDUMP if (1) ; else qDebug #endif -void Chunk::sweep() +bool Chunk::sweep() { + bool hasUsedSlots = false; SDUMP() << "sweeping chunk" << this; HeapItem *o = realBase(); bool lastSlotFree = false; @@ -316,6 +317,7 @@ void Chunk::sweep() } } objectBitmap[i] = blackBitmap[i]; + hasUsedSlots |= (blackBitmap[i] != 0); blackBitmap[i] = 0; extendsBitmap[i] = e; lastSlotFree = !((objectBitmap[i]|extendsBitmap[i]) >> (sizeof(quintptr)*8 - 1)); @@ -325,6 +327,7 @@ void Chunk::sweep() o += Chunk::Bits; } // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots."; + return hasUsedSlots; } void Chunk::freeAll() @@ -579,12 +582,21 @@ void BlockAllocator::sweep() // qDebug() << "BlockAlloc: sweep"; usedSlotsAfterLastSweep = 0; - for (auto c : chunks) { - c->sweep(); - c->sortIntoBins(freeBins, NumBins); -// qDebug() << "used slots in chunk" << c << ":" << c->nUsedSlots(); - usedSlotsAfterLastSweep += c->nUsedSlots(); - } + + auto isFree = [this] (Chunk *c) { + bool isUsed = c->sweep(); + + if (isUsed) { + c->sortIntoBins(freeBins, NumBins); + usedSlotsAfterLastSweep += c->nUsedSlots(); + } else { + chunkAllocator->free(c); + } + return !isUsed; + }; + + auto newEnd = std::remove_if(chunks.begin(), chunks.end(), isFree); + chunks.erase(newEnd, chunks.end()); } void BlockAllocator::freeAll() @@ -950,7 +962,8 @@ void MemoryManager::runGC() #ifndef QT_NO_DEBUG qDebug() << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots."; #endif - qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks"; + size_t oldChunks = blockAllocator.chunks.size(); + qDebug() << "Allocated" << totalMem << "bytes in" << oldChunks << "chunks"; qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore); dumpBins(&blockAllocator); @@ -975,6 +988,7 @@ void MemoryManager::runGC() qDebug() << "Used memory before GC:" << usedBefore; qDebug() << "Used memory after GC:" << usedAfter; qDebug() << "Freed up bytes:" << (usedBefore - usedAfter); + qDebug() << "Freed up chunks:" << (oldChunks - blockAllocator.chunks.size()); size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter; if (lost) qDebug() << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index db0ffe11a2..6e820dfc0f 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -59,6 +59,10 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct MarkStack; + +typedef void(*ClassDestroyStatsCallback)(const char *); + /* * Chunks are the basic structure containing GC managed objects. * @@ -175,7 +179,7 @@ struct Chunk { return usedSlots; } - void sweep(); + bool sweep(); void freeAll(); void sortIntoBins(HeapItem **bins, uint nBins); -- cgit v1.2.3