SGCL: Real-time garbage collector for C++(github.com)
github.com
SGCL: Real-time garbage collector for C++
https://github.com/pebal/sgcl
5 comments
In early attempts of removing GIL, atomic reference counting slows down performance by 60%. In comparison, tracing garbage collector can defer/coalesce reference counting. You can read more in [2] section 2.1, and this paper introduced a new referencing counting method.
[1] Multithreaded Python without the GIL https://docs.google.com/document/d/18CXhDb1ygxg-YXNBJNzfzZsD... [2] Low-Latency, High-Throughput Garbage Collection https://users.cecs.anu.edu.au/~steveb/pubs/papers/lxr-pldi-2...
[1] Multithreaded Python without the GIL https://docs.google.com/document/d/18CXhDb1ygxg-YXNBJNzfzZsD... [2] Low-Latency, High-Throughput Garbage Collection https://users.cecs.anu.edu.au/~steveb/pubs/papers/lxr-pldi-2...
Makes writing lock free data structures a heck of a lot easier. Entirely eliminates the ABA problem.
Unreal C++ and C++/CLI have one.
When one wants the flexibility of C++ with the productivity of a GC.
When one wants the flexibility of C++ with the productivity of a GC.
Whether GC improves productivity is a strong claim that needs a proof. I have yet to see such a proof.
So far my experience has been that (nondeterministic) GC is only a productivity improvement over languages with manual memory management like C, but a productivity degradation over languages with deterministic automatic memory management like C++ and Rust. GC manages only memory, while in the latter case, you get automatic management of resources of any type, which can be a huge productivity boost if you use it to your advantage.
So far my experience has been that (nondeterministic) GC is only a productivity improvement over languages with manual memory management like C, but a productivity degradation over languages with deterministic automatic memory management like C++ and Rust. GC manages only memory, while in the latter case, you get automatic management of resources of any type, which can be a huge productivity boost if you use it to your advantage.
Do you want an example for C++? Lock free data structures are PhD level skillset unless there is some kind of tracing GC algorithm being used.
Also RAII is great and all, yet there lots of ways to get it wrong.
Badly implemented destructors, missing virtual destructors in hierachys, throwing exceptions on destructurs, not using handle types on heap allocated data, incorrect pairing of allocators.
Also RAII is great and all, yet there lots of ways to get it wrong.
Badly implemented destructors, missing virtual destructors in hierachys, throwing exceptions on destructurs, not using handle types on heap allocated data, incorrect pairing of allocators.
Lock-free data structures is a 0.001% niche, which can be implemented as libraries by experts and then used without any trouble by an average Joe programmer. An average Joe wouldn't get the implementation of them right even in a GC language anyway. Also, in those niche cases, GC is available as an option. But you should not optimize the language for the niche use case.
> Badly implemented destructors, missing virtual destructors in hierachys, throwing exceptions on destructurs, not using handle types on heap allocated data, incorrect pairing of allocators.
Those seem to be more specific problems with C++ rather than RAII. Rust has none of those.
> Badly implemented destructors, missing virtual destructors in hierachys, throwing exceptions on destructurs, not using handle types on heap allocated data, incorrect pairing of allocators.
Those seem to be more specific problems with C++ rather than RAII. Rust has none of those.
The ongoing issues with Drop trait stabilization show otherwise.
Having a GC is an option alongside the other ones, an option that both Epic and Microsoft think it is worth enough money to spend development resources on.
And Google as well, actually, as Chrome uses a C++ GC, seen as way to fix security issues, Olipan.
Having a GC is an option alongside the other ones, an option that both Epic and Microsoft think it is worth enough money to spend development resources on.
And Google as well, actually, as Chrome uses a C++ GC, seen as way to fix security issues, Olipan.
GC as an opt in, next to to RAII - so you can use it when you need it, that's fine. But it is a productivity issue when the only way to manage memory is non-deterministic GC, e.g. like in Java or Go.
That was the original question, why there are GC implementations for C++.
Every language with a GC is distinct, and should be properly analysed instead of putting all into the same box.
Every language with a GC is distinct, and should be properly analysed instead of putting all into the same box.
Demanding proof is a cop out. From microservice architectures to line length limits, there's no proof for basically any engineering decisions we make daily.
GCs can be more efficient if you alloc/free memory very often. shared_ptr can be quite slow because of the bookkeeping. It can also help bring more consistent performance, ie. one big malloc instead of millions of small ones.
I would think destructors would negate some of the performance advantages of GCs, since it's not possible to have zero-cost freeing of objects when destructors exist.
SGCL executes the destructors in a separate thread, so there is no cost to the mutator.
> SGCL executes the destructors in a separate thread, so there is no cost to the mutator.
Firstly, that's orthogonal to my original point is that, for example, a semi-space nursery can significantly reduce the cost of short-lived allocations (often being faster than malloc/free on such a workload), but only if there are no destructors.
Secondly, threads typically share resources so running something on a different thread does not magically cause it to not disturb the mutator. Such a claim makes me start to doubt the "real-time" claim in the title...
Firstly, that's orthogonal to my original point is that, for example, a semi-space nursery can significantly reduce the cost of short-lived allocations (often being faster than malloc/free on such a workload), but only if there are no destructors.
Secondly, threads typically share resources so running something on a different thread does not magically cause it to not disturb the mutator. Such a claim makes me start to doubt the "real-time" claim in the title...
Disruption is a lower cost than the cost of executing the destructor by the mutator.
One example would be to create higher level languages that compile to / interoperable with C++
GC can be faster and allocate less memory.
tracked_ptr: 279.95ms (151MB)
shared_ptr: 1035.07ms (480MB)
source: https://godbolt.org/z/jP7ohPehY
tracked_ptr: 279.95ms (151MB)
shared_ptr: 1035.07ms (480MB)
source: https://godbolt.org/z/jP7ohPehY
This introduces the tracked smart pointer. This pointer has less overhead than shared_ptr and releases circular data structures.
You use custom memory management where it matters, gc anywhere else.
How does the LGPL get interpreted for a header-only library?
Makes it behave very similarly to GPL. LGPL requires any derivative to allow a user of that derivative to substitute the LGPL'd portion with a modified version. It's very difficult to perform such a substitution without providing substantial portions of the derivative's source code.
Version 3 is more liberal.
Did anyone check how it works?
I do not mean to detract from the author's work in any way, but how does one maintain a 2180 line file easily? I find these to be very difficult to grep and grok, even if I am the author of the entire file.
I was working on a 1.7k LOC file as I read your comment. To be honest I'm not sure I understand the question (how would splitting the file into two change anything in your view?), but one thing that I find helpful in general is my editor's ability to collapse method/class/etc. definitions. That lets me work on the function I want without being distracted by other definitions. Perhaps that's the answer to your question? But that's useful at 200 lines too, not just 2000 lines.
Honestly, 2200 LOC is really not very much. I’ve dealt with 15 kLOC source files before, and have seen upwards of 30 before. I don’t think breaking it up would add much in the way of clarity given the volume of code, at that point splitting it up is just about optimizing compile times.
In regards for how to grok and grep code like that, it’s just a skill like any other. I got very good at reading code and forming a mental model of it.
In regards for how to grok and grep code like that, it’s just a skill like any other. I got very good at reading code and forming a mental model of it.
When I have a large file, using multiple panes on the same file was a big step forward. It took me far longer than it should have to realize that.
Edit: Although 2k lines in file does not quite qualify as large in a lot of the projects. (Not that I like it, I prefer to break them up)
Edit: Although 2k lines in file does not quite qualify as large in a lot of the projects. (Not that I like it, I prefer to break them up)
The IDE component that displays the project hierarchy is necessary at this level. Visual studio displays all methods of all classes in the current file with combo boxes making it a lot easier to navigate.
Not necessary to use IDE either, there is e.g. Tagbar plugin for Vim
Oh, this is a great idea! I have to look into adding this to Emacs.
Modern text editors and IDEs have plenty of features to better find your way around in large source files. One objective advantage of putting the entire implementation code of a C or C++ library into one source file is that you can entirely get rid of private interface headers (also, as other have said, 2kloc in one file isn't really all that much).
'''
... but how does one maintain a 2180 line file easily? I find these to be very difficult to grep and grok, even if I am the author of the entire file.
'''
not sure about others, but i am using emacs with various tools f.e. for c++ these days, clangd as lsp-server, for c (long time ago) it was mostly cscope (via xcscope.el iirc) etc. etc.
not sure about others, but i am using emacs with various tools f.e. for c++ these days, clangd as lsp-server, for c (long time ago) it was mostly cscope (via xcscope.el iirc) etc. etc.
When it can't be avoided there were (rare) times that I used #includes to split what would have been one long source file into multiple files. (2k lines is still within my 1 file threshold, but I generally aim for less than 1k lines). Interestingly, C# has partial classes which I have also rarely manually used (automatically generated for forms).
Not only forms, nowadays it gets plenty of use via Roslyn code generators.
The simulation code we use is a 88kLOC Fortran77 file which is in continuous development since the eighties.
And that's just the main file, it uses several libraries for lower level operations.
And that's just the main file, it uses several libraries for lower level operations.
I'm not saying that it's a bad idea. I'm just curious about why/when garbage collection is better than conventional use of unique_ptr or shared_ptr.