Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core/state, trie: fix memleak from fastcache #26071

Closed
wants to merge 2 commits into from

Conversation

tsahee
Copy link

@tsahee tsahee commented Oct 30, 2022

Fastcache uses memory allocated by mmap, which is not garbage collected.
Data filled in the codeCache is therefore leaked when the stateDatabase is discarded (e.g. in StateAtBlock).
Same goes for cleans fastcache when used in the TrieDB.

Reset() doesn't unmap memory from the OS, but it does move all chunks to fastcache's global free chunk list, allowing it to be reused by later instances.

Fastcache is also used by the snapshot. I did not add Reset to those instances to minimize diff and because the snapshot is not regularly discarded. I can add cleaning that up as well if you wish.

@Ferrydh
Copy link

Ferrydh commented Oct 30, 2022 via email

@tsahee tsahee changed the title fix memleak by codecache in stateDatabase core/state, trie: fix memleak from fastcache Oct 30, 2022
db: trie.NewDatabaseWithConfig(db, config),
disk: db,
codeSizeCache: csc,
codeCache: fastcache.New(codeCacheSize),
}
runtime.SetFinalizer(cdb, (*cachingDB).finalizer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like it's unnecessary to use fastcache here as the codeCache. fastCache is mostly for caching large amount of data for GC-friendly purpose. Obviously not the case here.

@PlasmaPower
Copy link
Contributor

Another option would be to maintain an in-house fastcache fork, which would have a finalizer on caches that frees them like you'd expect from Go being a garbage collected language. The upstream fastcache library is also unmaintained, e.g. VictoriaMetrics/fastcache#66 . I'd be happy to implement this but I want to make sure it makes sense first.

@karalabe
Copy link
Member

karalabe commented Nov 1, 2022

Using finalizers is the wrong approach really, both in the library and in this code. The docs clearly state that Reset needs to be called. One option is to use the API correctly here, another is to use a caching library that does not need an explicit close mechanism.

@holiman
Copy link
Contributor

holiman commented Nov 1, 2022

One option is to use the API correctly here,

I looked into doing that -- calling Reset via a Close method on the database. It becomes a very large diff, touching a lot of tests, mainly.

I think we might be better off using a caching library which does not have it's own allocator. The code cache is a 64 MB cache (pretty tiny), we don't need a cache-on-steroids library for that little thing,

@rjl493456442
Copy link
Member

@holiman totally agree

@holiman
Copy link
Contributor

holiman commented Nov 2, 2022

To follow up
bigcache has a different memory model -- and does not need Close(). It should be enough to just let the gc collect it. That said, it does have a Close method, and it is needed in case the config.CleanWindow > 0, because if that has been set then it will spin up a goroutine to do cache cleaning.

The fact that Close is not needed in most cases is an implementation detail, though, and it feels a bit wrong to just assume it will always be the case and rely on it.

@holiman
Copy link
Contributor

holiman commented Nov 4, 2022

Thanks for bringing this to our attention, but we will not merge this PR, since we don't think the solution is the best. We'll probably use #26092 to fix the problem instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants