Live data from Hacker News

Spotting and avoiding heap fragmentation in Rust applications

svix.com

61–70 of 70 posts

Re: Spotting and avoiding heap fragmentation in Rust applications

#61

In some ways Rust is in the worst possible position in terms of language design when it comes to fragmentation. In a completely manually managed language like C or C++, you can handle fragmentation problems yourself by writing your own allocators or doing object pools to reuse previously allocated memory. You have control over fragmentation. In a garbage collected language like Java or C#, the runtime is able to move…

Rust lets you specify your own allocator. You can also swap it deeper down as this article describes. It’s no worse than C or C++.

Also unsafe Rust is a thing and exists precisely to enable programming at the extremely low level when abstractions tend to leak badly. It’s considered bad form to have it in web apps and other normal code but seeing it in a low level data structure or an allocator would not be unusual.

Managed languages and high level languages definitely do have an advantage here.

Re: Spotting and avoiding heap fragmentation in Rust applications

#62
post #15

Shouldn't this also be a much larger problem when deploying rust on embedded systems or in the kernel? How is that solved in these cases? Or is this not a problem at all?

The embedded code I write doesn’t use an allocator at all, so it’s not a problem there.

The day I started (time ago) to learn Rust I had trouble learning to map Error(s) and dynamic dispatching. My first thought was: "if I cannot escape dynamic dispatching (for example with crates that use it), I will never understand how to use Rust in embedded, because of Box". And as an embedded C developer, this is something I never understood. For example:

"Values can be boxed (allocated on the heap) by creating a Box" (https://doc.rust-lang.org/rust-by-example/std/box.html)

But then I see

    Box
everywhere, for example in https://github.com/oxidecomputer/hubris/search?q=dyn

Is Box really allocating here? Is the "Rust By Example" text incomplete?

Then I had to stop learning Rust for other reasons, but this doubt really hit me at the time.

Re: Spotting and avoiding heap fragmentation in Rust applications

#63
post #62

Earlier quoted context omitted.

The embedded code I write doesn’t use an allocator at all, so it’s not a problem there.

The day I started (time ago) to learn Rust I had trouble learning to map Error(s) and dynamic dispatching. My first thought was: "if I cannot escape dynamic dispatching (for example with crates that use it), I will never understand how to use Rust in embedded, because of Box ". And as an embedded C developer, this is something I never understood. For example: "Values can be boxed (allocated on the heap) by creating a…

Dynamic dispatch (the `dyn` keyword) and dynamic allocation are distinct in Rust. You'll see Box a lot in application-level code because the developer UX of boxed dynamic resembles a GC'd language like Java/Go, but they're not really coupled under the hood.

Dynamic dispatch allows you to call trait methods on values without knowing the concrete type of that value, similar to C++ virtual methods or a C-style manually constructed vtable. In an embedded context this will mostly show up as function parameters, since you can't move things around on the stack without knowing their size. You might also see references to a dyn value, like `&dyn SomeTrait` -- this is similar to `Box`, but is a borrowed reference and therefore doesn't imply allocation.

Your link to the Oxide Hubris repo is misleading you because the hits seem to be pretty much all in build-time helper scripts (`build.rs`) and other minor tooling. You'd want to look through the source of their main binary, which probably wouldn't use allocation just for error propagation.

Re: Spotting and avoiding heap fragmentation in Rust applications

#64
post #62

Earlier quoted context omitted.

The day I started (time ago) to learn Rust I had trouble learning to map Error(s) and dynamic dispatching. My first thought was: "if I cannot escape dynamic dispatching (for example with crates that use it), I will never understand how to use Rust in embedded, because of Box ". And as an embedded C developer, this is something I never understood. For example: "Values can be boxed (allocated on the heap) by creating a…

Dynamic dispatch (the `dyn` keyword) and dynamic allocation are distinct in Rust. You'll see Box a lot in application-level code because the developer UX of boxed dynamic resembles a GC'd language like Java/Go, but they're not really coupled under the hood. Dynamic dispatch allows you to call trait methods on values without knowing the concrete type of that value, similar to C++ virtual methods or a C-style manually…

> Your link to the Oxide Hubris repo is misleading you

Sorry about this. It wasn't intentional.

But just to confirm, Box always allocates? So dynamic dispatch is not recommended in embedded, and thus crates that uses dynamic dispatch and/or Box?

Re: Spotting and avoiding heap fragmentation in Rust applications

#65
post #64

Earlier quoted context omitted.

Dynamic dispatch (the `dyn` keyword) and dynamic allocation are distinct in Rust. You'll see Box a lot in application-level code because the developer UX of boxed dynamic resembles a GC'd language like Java/Go, but they're not really coupled under the hood. Dynamic dispatch allows you to call trait methods on values without knowing the concrete type of that value, similar to C++ virtual methods or a C-style manually…

> Your link to the Oxide Hubris repo is misleading you Sorry about this. It wasn't intentional. But just to confirm, Box always allocates? So dynamic dispatch is not recommended in embedded, and thus crates that uses dynamic dispatch and/or Box ?

Dynamic dispatch (dyn) in embedded is fine.

Dynamic allocation (Box) in embedded is not recommended.

`&dyn SomeTrait` is dynamic dispatch without dynamic allocation.

`Box` is dynamic allocation without dynamic dispatch.

Re: Spotting and avoiding heap fragmentation in Rust applications

#66
post #13

This article would've been a bit cooler if the conclusion wasn't "switch from default allocator to jemalloc" but instead "use jemalloc to prove something is wrong in the default allocator and track down + find a fix for what's wrong in the default allocator" Unless I misunderstood that the default Rust allocator, with high request bodies and concurrency, is always going to suffer unfixable heap fragmentation like dis…

I agree that there could have been a more satisfying conclusion, but it is worth noting that jemalloc isn't a panacea. I've seen issues similar to Svix in both Rust and C++ applications that were heavy on ephemeral allocations, and have fixed it by doing all of the following, depending on the specific process: * Switching from libc malloc to jemalloc * Switching from libc malloc to tcmalloc (dating myself a little bi…

> Heap fragmentation is just a reality of some allocation patterns without a GC runtime.

It is also a reality with a GC runtime, even a compacting one. Tracing GCs have acceptable performance only if the available memory is many times larger than the memory used. Technically this maybe isn't called fragmentation, but the effects are just as bad - the application uses much more memory than really needed.

Re: Spotting and avoiding heap fragmentation in Rust applications

#67

Earlier quoted context omitted.

Rust by default uses the platform allocator. Anything that's true of it's allocator performance is also true of C. Also, as the sibling comment said, when you are doing tight embedded, the solution is not to allocate things dynamically.

I’m curious when not allocating things dynamically, does that just get around all memory safety (other than temporal with array bounds checking). Essentially any language that does array bounds checking would be as safe as rust? Or am I missing anything? C does not technically do that, so rust is still safer. But zig would be the same in the embedded space as rust? Or is there anything I am missing?

Rust's compiler also makes sure you never modify a place in memory from more than one place.

Re: Spotting and avoiding heap fragmentation in Rust applications

#68

Earlier quoted context omitted.

I’m curious when not allocating things dynamically, does that just get around all memory safety (other than temporal with array bounds checking). Essentially any language that does array bounds checking would be as safe as rust? Or am I missing anything? C does not technically do that, so rust is still safer. But zig would be the same in the embedded space as rust? Or is there anything I am missing?

Rust's compiler also makes sure you never modify a place in memory from more than one place.

That’s true, but that would be fairly trivial to do in a C program with only stack variables. Just always have only 1 mutable reference.

Something like C++ or Zig could enforce those rules even more easily.

Re: Spotting and avoiding heap fragmentation in Rust applications

#69

Earlier quoted context omitted.

Rust's compiler also makes sure you never modify a place in memory from more than one place.

That’s true, but that would be fairly trivial to do in a C program with only stack variables. Just always have only 1 mutable reference. Something like C++ or Zig could enforce those rules even more easily.

Yeah, I don't disagree. Shame they never went direction and instead were like "REAL MEN DON'T PROTECT AGAINST BUGS! WE DON'T WRITE BUGS!". But oh well. That's why we have the more modern languages these days.

Re: Spotting and avoiding heap fragmentation in Rust applications

#70
post #52

Earlier quoted context omitted.

Yet again, averages don't always represent real life accurately.

theyre usually close enough, especially for estimating needs. 1 billion/year averages out to 30/second like i said before. You think they're bursting to 1000? maybe i could believe that. 10,000?100,000/second? its unlikely. this is all still scale that is handled by stable, gc languages.

Speed is not the only advantage of using Rust on the backend.
Post reply on HN