5
lorentz
1d

I had to debug a reference loop in my Rust codebase and I was gearing up to it all week assuming that it would be a nightmare. It turns out that 1) it was 4 refloops, not one and 2) each of them took about 10 minutes to find. The benefit of no GC is deterministic deallocation timing, and this means that you can just set breakpoints or print statements to the point where the object might get freed and see if it actually does.

Plus, in contrast to GC, this transparently works across programs; Usercode holds a reference to a tuple and there's a map deep in the interpreter to document that std holds references to the tuple elements, but the fact that std references the elements because of the tuple, and that the elements must be freed once the tuple is freed, is only known by std. However, this ends up behaving exactly as if the relationship was held in the interpreter, so users of the public API don't need to know about it.

Comments
  • 3
    A refloop is just like this?

    for (const auto& user : users) {

    user.print();

    }

    What would it have to do with deallocation? It's just a reference right?
  • 3
    @retoor No, it's just a sequence of values that keep each other alive forming a loop in the ownership graph and preventing any of them from getting freed. I guess reference cycle is a better term.
  • 4
    Before I switched to Rust, I mostly did JS and my job demands C# so I'm entirely too used to cycle-detecting GCs.
  • 2
  • 1
    @lorentz
    Can you give a minimal example in Rust? Hard to imagine that without liberal box usage.
  • 2
    @TrayKnots Even worse, it's liberal Rc usage. I made some less than ideal decisions. Here's the project if you have a strong stomach.

    https://github.com/lbfalvy/orchid/...

    The entrypoints are orcx and orchid-std for host and plugin, but their ownership structure is in orchid-host and orchid-extension respectively
  • 2
    I want to get this to feature parity with the original single-binary design quickly because it's in many regards still a prototype and I don't know yet how much I'll have to change once I start using the FFI to make it do useful things.
  • 2
    On second thought, it is not ready for reading. But if you want to peruse anyway, screenshot your favourite antipattern for me.
  • 3
    @lorentz I looked over it an all I got was: I am not smart enough to understand this in the time I am willing to spend.

    Cool project, though. Lots of usages of LocalBoxedFutures were removed and lots of pins added, plus a tokio feature. Did you just recently decide to use tokio and have to refactor everything now for it?
  • 2
    @TrayKnots it's executor agnostic and hopefully wasm-compatible, to be honest I didn't do the tokio bits until yesterday because I had to get really drunk to finally stop thinking holistically and just methodically design a solution step by step.

    The LocalBoxFuture removal was because AsyncFn was finally stabilized this Thursday so I applied it where possible.

    it's not supposed to be complicated, but it's a huge mess with a bunch of callbacks that shouldn't be callbacks and locks that are never contested. Once I fix the names and document everything it should be pretty easy to understand what's going on though, it should also highlight the worst factoring issues.
  • 3
    I just wanted to leave a comment and express my respect for what you are doing!
Add Comment