go-pkgz / lcw

Loading Cache Wrapper
https://go-pkgz.umputun.dev/lcw/
MIT License
20 stars 5 forks source link

Memory leak during heavy usage #45

Closed foobarbazmeow closed 1 month ago

foobarbazmeow commented 1 month ago

With a large cache load, some serious memory leaks are possible. The buckets in map[K]V are never reduced.

func TestBucketsLeak(t *testing.T) {
    const n = 1_000_000

    printAlloc := func() {
        stats := runtime.MemStats{}
        runtime.GC()
        runtime.ReadMemStats(&stats)
        t.Logf("alloc: %d Kb\n", stats.Alloc/1024)
    }

    lc, err := NewLoadingCache()
    assert.NoError(t, err)
    printAlloc()

    for i := 0; i < n; i++ {
        lc.Set(fmt.Sprintf("key-%d", i), fmt.Sprintf("val-%d", i))
    }
    printAlloc()

    lc.Purge()
    printAlloc()

    // Prevents optimization
    runtime.KeepAlive(lc)
}
=== RUN   TestBucketsLeak
    cache_test.go:213: alloc: 196 Kb
    cache_test.go:213: alloc: 150528 Kb
    cache_test.go:213: alloc: 56785 Kb
--- PASS: TestBucketsLeak (0.85s)
paskal commented 1 month ago

Thanks a lot for the report! I'll look into it.

paskal commented 1 month ago

To clarify the scope, this affects only expirable cache in the lcw v1. I can reproduce the report but couldn't find the root cause of it yet. Even explicitly setting cache.data to nil after purge doesn't release the memory.