diff options
author | Lars Knoll <lars.knoll@qt.io> | 2017-04-27 19:37:35 +0200 |
---|---|---|
committer | Robin Burchell <robin.burchell@crimson.no> | 2017-04-28 19:48:26 +0000 |
commit | 6a2febc680e163e56eb61d322d156dbf6fb07e0e (patch) | |
tree | 889a118a0410dff1312696f3841156f416c3833e | |
parent | 4a4a8e911cfafcff069de0c1acb2462974166938 (diff) |
Fix memory leak in the memory manager
There was a bug in Chunk::sweep() that would lead
to parts of the memory not being freed as it should
have been.
This happened when an object 'overflowed' into the
next index of the estendBitmap, where we then would
not correctly clear the extends bits.
Fixes performance degradation in qmlbench's
delegates_item_empty_jscreation.qml over multiple runs.
Change-Id: Ia2cecd2ff218e4258a067a74631b5479589b7a7e
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Reviewed-by: Robin Burchell <robin.burchell@crimson.no>
-rw-r--r-- | src/qml/memory/qv4mm.cpp | 34 |
1 files changed, 32 insertions, 2 deletions
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 88912a6678..7aa8f91503 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -262,17 +262,36 @@ void ChunkAllocator::free(Chunk *chunk, size_t size) Q_ASSERT(false); } +#ifdef DUMP_SWEEP +QString binary(quintptr n) { + QString s = QString::number(n, 2); + while (s.length() < 64) + s.prepend(QChar::fromLatin1('0')); + return s; +} +#define SDUMP qDebug +#else +QString binary(quintptr) { return QString(); } +#define SDUMP if (1) ; else qDebug +#endif void Chunk::sweep() { - // DEBUG << "sweeping chunk" << this << (*freeList); + SDUMP() << "sweeping chunk" << this; HeapItem *o = realBase(); + bool lastSlotFree = false; for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) { Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects quintptr toFree = objectBitmap[i] ^ blackBitmap[i]; Q_ASSERT((toFree & objectBitmap[i]) == toFree); // check all black objects are marked as being used quintptr e = extendsBitmap[i]; - // DEBUG << hex << " index=" << i << toFree; + SDUMP() << " index=" << i; + SDUMP() << " toFree =" << binary(toFree); + SDUMP() << " black =" << binary(blackBitmap[i]); + SDUMP() << " object =" << binary(objectBitmap[i]); + SDUMP() << " extends =" << binary(e); + if (lastSlotFree) + e &= (e + 1); // clear all lowest extent bits while (toFree) { uint index = qCountTrailingZeroBits(toFree); quintptr bit = (static_cast<quintptr>(1) << index); @@ -299,6 +318,10 @@ void Chunk::sweep() objectBitmap[i] = blackBitmap[i]; blackBitmap[i] = 0; extendsBitmap[i] = e; + lastSlotFree = !((objectBitmap[i]|extendsBitmap[i]) >> (sizeof(quintptr)*8 - 1)); + SDUMP() << " new extends =" << binary(e); + SDUMP() << " lastSlotFree" << lastSlotFree; + Q_ASSERT((objectBitmap[i] & extendsBitmap[i]) == 0); o += Chunk::Bits; } // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots."; @@ -887,6 +910,13 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true) if (printOutput) qDebug() << " number of entries in slot" << i << ":" << nEntries; } + SDUMP() << " large slot map"; + HeapItem *h = b->freeBins[BlockAllocator::NumBins - 1]; + while (h) { + SDUMP() << " " << hex << (quintptr(h)/32) << h->freeData.availableSlots; + h = h->freeData.next; + } + if (printOutput) qDebug() << " total mem in bins" << totalFragmentedSlots*Chunk::SlotSize; return totalFragmentedSlots*Chunk::SlotSize; |