From 959e53c7519dce8b671bf2f7ee2a18bad5f7456c Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Fri, 24 Nov 2023 13:16:56 +0200 Subject: [PATCH] fastcache.go: re-create the bucket.m map inside cleanLocked() in order to reduce map fragmentation Hopefully, this may help reducing memory usage and GC pressure for long-running processes, which use fastcache. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5379 --- fastcache.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/fastcache.go b/fastcache.go index 092ba37..046af6c 100644 --- a/fastcache.go +++ b/fastcache.go @@ -272,13 +272,27 @@ func (b *bucket) cleanLocked() { bGen := b.gen & ((1 << genSizeBits) - 1) bIdx := b.idx bm := b.m - for k, v := range bm { + newItems := 0 + for _, v := range bm { gen := v >> bucketSizeBits idx := v & ((1 << bucketSizeBits) - 1) if (gen+1 == bGen || gen == maxGen && bGen == 1) && idx >= bIdx || gen == bGen && idx < bIdx { - continue + newItems++ } - delete(bm, k) + } + if newItems < len(bm) { + // Re-create b.m with valid items, which weren't expired yet instead of deleting expired items from b.m. + // This should reduce memory fragmentation and the number Go objects behind b.m. + // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5379 + bmNew := make(map[uint64]uint64, newItems) + for k, v := range bm { + gen := v >> bucketSizeBits + idx := v & ((1 << bucketSizeBits) - 1) + if (gen+1 == bGen || gen == maxGen && bGen == 1) && idx >= bIdx || gen == bGen && idx < bIdx { + bmNew[k] = v + } + } + b.m = bmNew } }