fitzgen / bumpalo

A fast bump allocation arena for Rust
https://docs.rs/bumpalo
Apache License 2.0
1.36k stars 111 forks source link

Memory Leak using bumpalo #147

Closed sundy-li closed 2 years ago

sundy-li commented 2 years ago

Codes:

#[derive(Debug)]
struct A {
    idx: i32,
    value: Option<Vec<u8>>,
}

impl Drop for A {
    fn drop(&mut self) {
        println!("Dropping {:?}", self.idx);
    }
}

#[test]
fn test_memory_leak() -> Result<()> {
    {
        let arena = Bump::new();
        let val = arena.alloc(A {
            idx: 0,
            value: Some(vec![1, 2, 3]),
        });

        let n = vec![0u8; 10485760000];
        let n = n.as_slice();
        val.value = Some(n.to_vec());
        println!("{:?}", "DROP ARENA");
    }

    println!("{:?}", "EXIT");
    std::thread::sleep(Duration::from_secs(100));
    Ok(())
}

using top to watch the RES memory after running above tests:

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
  48153 sundy     20   0   26.2g   9.8g  16768 S   0.0  31.2   0:03.24 it-36df462d7eae
fitzgen commented 2 years ago

This is expected behavior.

You are allocating a structure which contains a std::vec::Vec<T> in it and implicitly drops the Vec<T> when the structure is dropped. Bump does not run Drop implementations of things allocated inside it (as documented in the readme, crate-level docs, and docs for Bump) and it is std::vec::Vec<T>'s drop that deallocates the underlying heap storage. Therefore the heap storage is never reclaimed.

You can use bumpalo::collections::Vec<T> instead, which will allocate space for its entries from a Bump and which will run each elements' drop implementation.

sundy-li commented 2 years ago

Thanks, what about other collections if I need? eg: HashSet, HashMap

fitzgen commented 2 years ago

The hashbrown crate has hash sets and maps that can be parameterized by an allocator, and you can enable the nightly allocator trait implementation in this crate to use Bump with them.