EmbarkStudios / rpmalloc-rs

🐏 rpmalloc global memory allocator for Rust 🦀
http://embark.rs
Apache License 2.0
136 stars 14 forks source link

Heap grows linearly over time / the allocator seems to leak memory #7

Open Boscop opened 4 years ago

Boscop commented 4 years ago

When I use rpmalloc as global allocator, my application seems to allocate increasingly more memory linearly, aka it doesn't free memory when it should:

image (And it grows further as time goes on..)

I'm not sure if this is intended to behave this way, but I think it can't be. My application is very cyclic (frame-based), each frame uses the same types of same sizes that are allocated, thus it can't be that this linearly increasing allocation pattern is caused by allocating too many different sized blocks.

For comparison, when I don't use rpmalloc, but the default system allocator, the heap usage stays bounded, below like 80 MB:

image

This is on Win 8.1 btw. The only change between both runs is that for the second one I removed this:

#[global_allocator]
static ALLOC: rpmalloc::RpMalloc = rpmalloc::RpMalloc;
repi commented 4 years ago

Interesting, not seeing that behavior in our app. Running on Windows 10 (though doesn't feel like that should make a difference).

Is this single threaded or does it allocate from a lot of different threads every frame?

Boscop commented 4 years ago

@repi It's multi-threaded, but not doing anything crazy. I spawn 10 threads for different things and actix apparently spawns like 8. But one thread is doing the bulk of the processing, that one probably also allocates the most (small things every frame), I don't know about actix's allocation behavior (I'm sending & receiving a lot of small websocket msgs to my frontend).. Also, I'm sending msgs over std mpsc channels between the threads (state view updates & action msgs that cause another thread to do something), most at like 30 fps but some more frequently. So the sending thread is allocating space for a msg in the channel and the receiving thread has to deallocate it, right? Maybe that's causing it? I'm also storing a StateView inside a global static ArcSwap at 30 fps (instead of sending it via channels to all threads that need it):

pub static STATE_VIEW: Lazy<ArcSwap<StateView>> = Lazy::new(|| ArcSwap::new(Arc::new(StateView::default())));

Maybe those instances from each update don't get deallocated for some reason?

image