3 ms·
In other words, Rust's automagical memory deallocation is NOT a zero-cost abstraction: fn get_len1(things: HeavyThings) -> usize { things.len() }
by cs702 6y ago
In other words, Rust's automagical memory deallocation is NOT a zero-cost abstraction:
fn get_len1(things: HeavyThings) -> usize {
things.len()
}
fn get_len2(things: HeavyThings) -> usize {
let len = things.len();
thread::spawn(move || drop(things));
len
}
The OP shows an example in which a function like get_len2 is 10000x faster than a function like get_len1 for a hashmap with 1M keys.
See also this comment by chowells: https://news.ycombinator.com/item?id=23362925 https://news.ycombinator.com/item?id=23362925
- DasIch 6y agoNothing about how Rust handles deallocation is magical in any way. It's also definitely a zero-cost abstraction as I can see because the manual solution that's equivalent to get_len1() would be to essentially call free() on things. That would ultimately suffer from the same problem.
- cs702 6y agoYeah, you're right. In hindsight this was a poorly thought-out and poorly written post on my part.
- dathinab 6y agoNo the zero-cost refers to the abstraction (and runtime cost), which still is zero-cost. Deallocating is part of the normal work load not the abstraction. Also this isn't rust specific. Most (all?) RAII languages are affected and many GC approaches have this effect, too. Some do add additional abstraction to magically always or sometimes put the de-allocation into another thread. But de-allocating in another thread is not generally good or bad. There are a lot of use-cases where doing so is rather bad or can't be done (in case TLS is involved). Rust and other similar RAII languages at least let you decide what you want to do. Now it's (I think) generally known that certain kinds (not all) of GC do make some thinks simpler for GUI-like usage. Through they also tend to have less control. Note that it's a common pattern for small user CLI facing tools (which are not GC'ed) to leak resources instead of cleaning them up properly. You can do so in rust too if you want but it's a potential problem for longer running applications. Also here is a faster get `get_len` then both which is also more idiomatic rust then both: ``` fn get_len1(things: &HeavyThings) -> usize { things.len() } ``` If you have a certain thread (e.g. UI thread) in which you never want to do any cleanup work you can consider using a container like: ``` struct DropElsewhere<T: Send>(pub Option<T>); impl<T: Send> Drop for DropElsewhere<T> { fn drop(&mut self) { if let Some(value) = self.take() { thread::spawn(move || drop(value)); } } } ``` You can optimize this with `ManualDrop` to have close to zero-runtime overhead (removes the `take` and `if let` part).
- cs702 6y ago> No the zero-cost refers to the abstraction (and runtime cost), which still is zero-cost. Deallocating is part of the normal work load not the abstraction. Yeah, you're right. In hindsight my comment was poorly thought-out and poorly written.