Skip to content(if available)orjump to list(if available)

Garbage collection for Rust: The finalizer frontier

gwbas1c

> Having acknowledged that pointers can be 'disguised' as integers, it is then inevitable that Alloy must be a conservative GC

C# / dotnet don't have this issue. The few times I've needed a raw pointer to an object, first I had to pin it, and then I had to make sure that I kept a live reference to the object while native code had its pointer. This is "easier done than said" because most of the time it's passing strings to native APIs, where the memory isn't retained outside of the function call, and there is always a live reference to the string on the stack.

That being said, because GC (in this implementation) is opt-in, I probably wouldn't mix GC and pointers. It's probably easier to drop the requirement to get a pointer to a GC<T> instead of trying to work around such a narrow use case.

gwbas1c

Before making criticisms that Garbage Collection "defeats the point" of Rust, it's important to consider that Rust has many other strengths:

- Rust has no overhead from a "framework"

- Rust programs start up quickly

- The rust ecosystem makes it very easy to compile a command-line tool without lots of fluff

- The strict nature of the language helps guide the programmer to write bug-free code.

In short: There's a lot of good reasons to choose Rust that have little to do with the presence or absence of a garbage collector.

I think having a working garbage collection at the application layer is very useful; even if it, at a minimum, makes Rust easier to learn. I do worry about 3rd party libraries using garbage collectors, because they (garbage collectors) tend to impose a lot of requirements, which is why a garbage collector usually is tightly integrated into the language.

jvanderbot

You've just listed "Compiled language" features. Only the 4th point has any specificity to Rust, and even then, is vague in a way that could be misinterpreted.

Rust's predominant feature, the one that brings most of its safety and runtime guarantees, is borrow checking. There are things I love about Rust besides that, but the safety from borrow checking (and everything the borrow checker makes me do) is why I like programming in rust. Now, when I program elsewhere, I'm constantly checking ownership "in my head", which I think is a good thing.

gwbas1c

Oh no, I'm directly criticizing C/C++/Java/C#:

The heavyweight framework (and startup cost) that comes with Java and C# makes them challenging for widely-adopted lightweight command-line tools. (Although I love C# as a language, I find the Rust toolchain much simpler and easier to work with than modern dotnet.)

Building C (and C++) is often a nightmare.

procaryote

Hello world in java is pretty fast. Not rust fast but a lot faster than you'd expect.

Java starting slowly is mostly from all the cruft in the typical java app, with springboot, dependency injection frameworks, registries etc. You don't have to have those, it's just that most java devs use them and can't conceive of a world of low dependencies

Still not great for commandline apps, but java itself is much better than java devs

ComputerGuru

New AOT C# is nice, but not fully doable with the most common dependencies. It addresses a lot of the old issues (size, bloat, startup latency, etc)

hypeatei

> The heavyweight framework

Do you mean the VM/runtime? If so, you might be able to eliminate that with an AOT build.

> I find the Rust toolchain much simpler and easier to work with than modern dotnet

What part of the toolchain? I find them pretty similar with the only difference being the way you install them (with dotnet coming from a distro package and Rust from rustup)

jrop

Just going to jump in here and say that there's another reason I might want Rust with a Garbage Collector: The language/type-system/LSP is really nice to work with. There have indeed been times that I really miss having enums + traits, but DON'T miss the borrow checker.

tuveson

Maybe try a different ML-influenced language like OCaml or Scala. The main innovation of Rust is bringing a nice ML-style type system to a more low level language.

zamalek

- Rust is a nice language to use

tayo42

What other language has modern features like rust and is compiled?

procaryote

it depends completely on what you put in "modern features"

gizmo686

Also, the proposed garbage collector is still opt in. Only pointers that are specifically marked as GC are garbage collected. This means that most references are still cleaned up automatically when the owner goes out of scope. This greatly reduces the cost of GC compared to making all heap allocations garbage collected.

This isn't even a new concept in Rust. Rust already has a well accepted RC<T> type for reference counted pointers. From a usage perspective, GC<T> seems to fit in the same pattern.

zigzag312

Language where most of the libraries are without GC, but has an GC opt in would be interesting. For example only your business logic code would use GC (so you can write it more quickly). And parts where you don't want GC are still written in the same language, avoiding the complexity of FFI.

rixed

In all honesty, there are three topics I try to refrain myself from engaging with on HN, often unsuccesfully: politics, religion, and rust.

I don't know what you had to go through before reaching rust's secure haven, but what you just said is true for the vast majority of compiled languages, which are legions.

yoyohello13

I love the rust ecosystem, syntax, and type system. Being able to write Rust without worrying about ownership/lifetimes sounds great honestly.

James_K

Go is probably a better pick in this case.

torginus

While I'm not ideologically opposed to GC in Rust I have to note:

- the syntax is hella ugly

- GC needs some compiler machinery, like precise GC root tracking with stack maps, space for tracking visted objects, type infos, read/write barriers etc. I don't know how would you retrofit this into Rust without doing heavy duty brain surgery on the compiler. You can do conservative GC without that, but that's kinda lame.

taylorallred

For those who are interested, I think that arena allocation is an underrated approach to managing lifetimes of interconnected objects that works well with borrow checking.

Dwedit

There was one time where I actually had to use object resurrection in a finalizer. It was because the finalizer needed to acquire a lock before running destruction code. If it couldn't acquire the lock, you resurrect the object to give it a second chance to destroy (calling GC.ReRegisterForFinalize)

nu11ptr

While it might be useful for exploration/academic pursuit/etc., am I the only one who finds "conservative GC" a non-starter? Even if this was fully production ready, I had a use case for it, etc. I still would never ship an app with a conservative GC. It is difficult enough to remove my own bugs and non-determinism, and I just can't imagine trying to debug a memory leak caused due to a conservative GC not finding all used memory.

ltratt

If you've used Chrome or Safari to read this post, you've used a program that uses (at least in parts) conservative GC. [I don't know if Firefox uses conservative GC; it wouldn't surprise me if it does.] This partly reflects shortcomings in our current compilers and in current programming language design: even Rust has some decisions (e.g. pointers can be put in `usize`s) that make it hard to do what would seem at first glance to be the right thing.

king_terry

The whole point of Rust is to not have a garbage collector while not worrying about memory leaks, though.

IainIreland

One clear use case for GC in Rust is for implementing other languages (eg writing a JS engine). When people ask why SpiderMonkey hasn't been rewritten in Rust, one of the main technical blockers I generally bring up is that safe, ergonomic, performant GC in Rust still appears to be a major research project. ("It would be a whole lot of work" is another, less technical problem.)

For a variety of reasons I don't think this particular approach is a good fit for a JS engine, but it's still very good to see people chipping away at the design space.

Manishearth

Worth highlighting: library-level GC would not be convenient enough to use pervasively in Rust anyway. library-level GC does not replace Rust's "point".

It's useful to have when you have complex graph structures. Or when implementing language runtimes. I've written a bit about these types of use cases in https://manishearth.github.io/blog/2021/04/05/a-tour-of-safe...

And there's a huge benefit in being able to narrowly use a GC. GCs can be useful in gamedev, but it's a terrible tradeoff to need to use a GC'd language to get them, because then everything is GCd. library-level GC lets you GC the handful of things that need to be GCd, while the bulk of your program uses normal, efficient memory management.

GolDDranks

The mechanisms that Rust provide for memory management are various. Having a GC as a library for usecases with shared ownership / handles-to-resources is not out of question. The problem is that they have been hard to integrate with the language.

jvanderbot

While you're of course correct, there's just something that feels off. I'd love if we kept niche, focused-purpose languages once in a while, instead of having every language do everything. If you prioritize everything you prioritize nothing.

GolDDranks

I agree specifically with regards to GC; I think that focusing on being an excellent language for low-level programming (linkable language-agnostic libraries, embedded systems, performance-sensitive systems, high-assurance systems etc.) should continue being the focus.

However, this is 3rd party research. Let all flowers bloom!

sebastianconcpt

> If you prioritize everything you prioritize nothing

Well...

If you prioritize everything you prioritize generalism.

(the "nothing" part comes from our natural limitation to pay enough multidisciplinary attention to details but that psychological impression is being nuked with AI as we speak and the efforts to get to AGI are an attempt to make synthetic "intelligence" be able to gain dominion over this spirit before us)

bryanlarsen

Just like when hiring developers, there's an advantage in choosing "jack of all trades, master of some".

hedora

Yeah; I wished they'd gone the other way, and made memory leaks unsafe (yes, this means no Rc or Arc). That way, you could pass references across async boundaries without causing the borrow checker to spuriously error out.

(It's safe to leak a promise, so there's no way for the borrow checker to prove an async function actually returned before control flow is handed back to the caller.)

dzaima

Same as with GC, neither need be a fixed choice; having a GC library/feature in Rust wouldn't mean that everything will be and must be GC'd; and it's still possible to add unleakable types were it desired: https://rust-lang.github.io/keyword-generics-initiative/eval... while keeping neat things like Rc<T> available for things that don't care. (things get more messy when considering defaults and composability with existing libraries, but I'd say that such issues shouldn't prevent the existence of the options themselves)

James_K

Actually, memory leaks are the major class of memory error for which Rust offers no protection. See the following safe function in Box:

https://doc.rust-lang.org/std/boxed/struct.Box.html#method.l...

gizmo686

Rust's memory safety guarantees do not insure the absence of leaks. However, Rust's design does offer significant protection against leaks (relative to languages like C where all heap allocations must be explicitly freed).

The fact that any felt it nessasary to add a "leak" function to the standard library should tell you something about how easy it is to accidentally leak memory.

ape4

If only there was a C++-like language with garbage collection (Java, C#, etc)

jerf

I can't be an expert in every GC implementation because there are so many of them, but many of the problems they mention are problems in those languages too. Finalizers are highly desirable to both the authors of the runtimes and the users of the languages, but are generally fundamentally flawed in GC'd languages, to the point that the advice in those languages is to stay away from them unless you really know what you are doing, and then, to stay away from them even so if you have any choice whatsoever... and that's the "solution" to these problems most languages end up going with.

Which does at least generally work. It's pretty rare to be bitten by these problems, like, less-than-once-per-career levels of rare (if you honor the advice above)... but certainly not unheard of, definitely not a zero base rate.

reactordev

Latest version of C# is a fantastic choice for this. Java too but I would lean more C# due to the new delegate function pointers for source-generated p/invoke. Thing of beauty.