-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
som-gc
: Custom Mark-and-Sweep Garbage Collector
#33
base: master
Are you sure you want to change the base?
Conversation
Something else to note is that the library, as implemented right now, is unsound. This is because simply storing a
Fixing this rooting problem is non-trivial and explained in detail in this blog post by manishearth, the author of the I'll do revisions to the library's API surface to try to mitigate this issue as much as I can, over time. |
som-gc
**: Custom Mark-and-Sweep Garbage Collectorsom-gc
: Custom Mark-and-Sweep Garbage Collector
Oh, nice. So, how does this work? You got The problem you describe with missing roots is indeed pretty common. Some systems deal with that by having enough head room, and when they are in a code section that may have room, they prevent GC, i.e., delay it until it is save. |
Yeah, every type that is GC-allocated is accessed through a For tracing, all types that want to be allocated in the GC heap must implement the let mut heap = GcHeap::new();
// Consider `MyType` to be a struct that implements the `Trace` trait.
let a: Gc<MyType> = heap.allocate(MyType::new());
let b: Gc<MyType> = heap.allocate(MyType::new());
heap.collect_garbage(|| {
a.trace();
});
// Only objects reachable from `a` will be kept.
// All other objects gets deallocated. This example also shows why this library is unsound. The But I am not sure which route I personally want to take yet.
Do you mean having code sections where the GC is guaranteed to not run ? |
Yes, exactly. I have seen systems that use things like: /* ... */
disable_gc();
/* mess with stuff */
reenable_gc();
Hm, any specific reason to go with a linked list? |
The reason it is a linked list is because the allocated types can be different, which means their size may not be the same, so I can't use a |
Hm, I see. Yeah makes sense. |
e1063d1
to
7ee4580
Compare
Hey Nicolas, I was taking another look at som-rs to see how its performance could be improved. Were there good performance gains from using this GC, have you measured anything? Though I'm not sure it's finished since you mention something about it stagnating in #37 |
I did some measurements, and currently the GC is a considerable performance hit. On my machine, here are the speedup ratios compared to the current master branch, for both the system allocator (the default
So yeah, the GC is quite a bit slower than using I mentioned that it was currently stagnating mainly due to my technical knownledge of memory allocators (I considered maybe writing my own I have some other easier ideas I'd like to implement to improve the GC, but I could not dedicate much time to this with my current situation, so it hasn't been done yet. |
I've also noticed that the people over at the Software Development Team from King's College London recently forked this project and are apparently pursuing integrating Alloy (their own GC solution, using a custom Rust compiler toolchain) into SOM-RS. I think it is a really cool prospect and I am quite excited to see how it turns out, and what differences will there be with yksom (their own SOM interpreter written in Rust). Their GC solution, being integrated into the compiler and being able to influence the codegen, is likely to always be faster than whatever I'll be able to come up with on my own, using stable regular Rust. But I don't think it will make me stop my efforts towards improving this current GC, even if it is just for my own learning. |
Here are the benchmark results for AST interpreter
Bytecode interpreter
|
feat: more trait impls for `Gc<T>`
Here are the benchmark results for AST interpreter
Bytecode interpreter
|
Here are the benchmark results for AST interpreter
Bytecode interpreter
|
This PR introduces a new crate within the
som-rs
workspace, calledsom-gc
.It is an implementation of a mark-and-sweep garbage collector as a Rust library.
Automatic memory management and reclamation is a quite new territory for me, as I have been reading about and researching on my free time for a while now, but never wrote anything like it yet.
Therefore, the initial implementation in this PR is rather simple compared to what's eventually possible.
I plan to improve the implementation as time goes on and as my knowledge of better GC techniques grows.
This PR also already changes
som-interpreter-bc
to integrate this new GC, as a replacement of the reference-counting method that it previously used.The integration is already complete, all instance of reference-counting is now gone and the SOM primitives that were previously unable to be implemented (
System>>#fullGC
andSystem>>#gcStats
) are now available and passing the tests.The performance of this GC, however, is a notable regression from reference-counting, from my initial measurements.
Since the implementation is rather simple right now, this was to be expected and I hope to make it better progressively over time.
The inclusion of a tracing garbage collector also allows to finally address the memory leak issue that could happen when reference cycles occurred (when two SOM values references each other, directly or indirectly).