News for hackers. Stuff that matters.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by torginus on Sunday January 21, 2024 @07:44AM (#39077949)
Ah the spectre of the 80s, most famously used by the ancient fork of Mono that Unity uses, leading to GC-pause induced stutters that have plagued gaming for over a decade.

I'd estimate that the bad rap GC languages get can be traced back to this piece of code.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by mihaaly on Sunday January 21, 2024 @08:21AM (#39078194)
I assume that real time computing should have used real time computing compatible techniques. But luckily those exposed to other than games and game development might feel less aversion towards GC, probably even the other way around.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by p_l on Sunday January 21, 2024 @07:55AM (#39078023)
Mono is nowhere close to major use case of it, it has been succesfully deployed in maaaany projects.

C++ crazies denigrating GC even when it visibly fixed their issues, or maybe especially when it did, was a phenomenon since 1990. Even when code with Boehm GC ran faster - and most importantly, didn't crash all the time.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Sunday January 21, 2024 @08:14AM (#39078159)
How did GC visibly fix their issues?

Manually managed code doesn't crash all the time. It probably crashed way more in the 90s. There is an art to writing manually managed code that is maintainable and fast, sure, and it doesn't involve malloc() and free(). And then there is RAII, automating lots of the work.

The C++ crazies are AFAICS still most everywhere where there is lots of temporary objects and serious requirements on throughput & latency. There are frameworks and languages that support garbage collection that get used in this space too, but I don't know how much can be inferred from that.

Seems like C and C++ guys are constantly looking for ways to automate their garbage cleanup.

And seems like GC guys are constantly looking for ways to fix their web-of-objects memory layout, and to prevent GC from ruining their performance. Plus, GC isn't deterministic, it mostly works for memory but otherwise you'll see _lots_ of manual cleanup code (not actually making use of the GC for this cleanup type code), and it always feels a bit tricky with the GC still being part of the game. Not that I take a huge issue with C-like cleanup code -- I think RAII can be tricky too because it's hard to "read" what happens. But compared to GC, at least RAII is deterministic.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pjmlp on Sunday January 21, 2024 @08:40AM (#39078342)
The deterministic myth only works out for basic types, see Herb Stutter CppCon 2015 talk on the matter, and how performance workarounds turn out a poor man's GC.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by josefx on Sunday January 21, 2024 @09:36AM (#39078786)
That is a one and a half our long talk, can you point to the timestamp where he talks about determinism?

> and how performance workarounds turn out a poor man's GC.

If you need performance then it doesn't matter if it is a "poor mans GC", what matters is that it meets the space/time requirements, most general purpose GC tend to care about neither.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pjmlp on Sunday January 21, 2024 @10:01AM (#39079022)
The only deterministic thing is the call point, Herb points out that just like calling malloc()/free() it is not possible to deterministically assert the execution time, more so with complex data structures where not only there is a domino effect of destructors being called, there is also the possibility of causing stack overflows if the destuctors are written incorrectly, to build an argument for presenting his deferred pointer class, which is basically a GC in disguise.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Sunday January 21, 2024 @10:51AM (#39079499)
That is an obvious thing, and totally besides the point. Also, probably GC only helps little against this. Sure, actually calling the destructor can be delayed in order to even out latency. You can do the same with RAII.

Sometimes you can't do that though because you have certain constraints on the execution order of whatever routines you need to run. This is completely independent of whether you use manual cleanup or GC or RAII, however with GC it is weird/hard/impossible to synchronize the GC with the non-cleanup code.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by SleepyMyroslav on Monday January 22, 2024 @08:45AM (#39089445)
I have anecdata to add to Herbs point.

I had a AAA project hitting 30ms pauses in free() implementation by platform vendor for quite popular gaming platform in 2016. Ofc it is anecdata but having actual deadlines from implementations is really hard. I had to replace malloc/free implementation like 3 month before ship date to avoid the issue.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Monday January 22, 2024 @02:19PM (#39094057)
free != destructor, that's the important point here.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Sunday January 21, 2024 @08:51AM (#39078406)
What? RAII is totally deterministic, not sure what you want to contend here. CppCon 2015: Herb Sutter "Writing Good C++14... By Default": Not sure where I'm going to find my answer here.

Anyway, for complex state that must be cleaned up, maybe flushed before etc., you'll always find a lot of manual cleanup code, or otherwise find code with lots of random problems, often unreported. That is true both for GC languages as well as C++ and other languages with RAII or RAII-likes.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pjmlp on Sunday January 21, 2024 @09:53AM (#39078942)
Unless you can static assert how long each destructor takes, it is not deterministic, even less if ownership is given to background threads for cleanup like on C++/WinRT.

The talk is "Leak-Freedom in C++", 2016 actually, https://youtu.be/JfmTagWcqoE?si=MY1JnWyybh5K8I8-

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Sunday January 21, 2024 @10:01AM (#39079023)
What I want to say here is the most basic thing. The order in which the destructors get called (also in the context of the other code) is deterministic. GC doesn't give you that. It should be obvious what I said.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pjmlp on Sunday January 21, 2024 @10:04AM (#39079049)
Even that depends if constructors/destructors are ellided when UB or LTO are part of the picture.

An optimization that coroutines rely upon as means to remove the abstractions of their execution.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Sunday January 21, 2024 @10:12AM (#39079144)
UB? What? That's completely off-topic. Please stop that, it's annoying.

I can't imagine what LTO should have to do with that either, but if there's any substance here please enlighten me.

The order in which destructors get called is well defined (and generally useful insofar as it's the reverse order of construction). Can't you just accept a simple argument? I'm not even a huge fan of RAII, but it has its uses.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by nwlieb on Sunday January 21, 2024 @04:13PM (#39083132)
There's some ambiguity for argument destruction order for example: https://stackoverflow.com/a/36992250

Similarly, the construction/destruction order for std::tuple elements is not well defined.

Granted, that's implementation defined behavior, which is technically deterministic on a single compiler.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Sunday January 21, 2024 @05:11PM (#39083607)
This isn't really about constructors/destructors. Expressions like function calls with multiple arguments have always been "unsequenced" with respect to each other. In other words the order is left to decide for the compiler. It's always been like that, going back to C (and probably other languages). If you call f(x++, x++) what values get passed to f is unspecified.

I suppose the destruction of whatever the expressions constructed still happens in reverse order of construction.

But either way I might not even care, I'm aware that at the level of a single statement the execution sequences aren't much defined, so I rarely put more than one mutating thing per expression, or otherwise I'm sure that I don't care about the order -- I could live with any sequence as well as totally parallel execution.

Example: buf[i++] = 5 has 2 mutating sub-expressions, but I know it's not messing up anything. I don't care whether i gets incremented before 5 gets assigned or the other way around.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by einpoklum on Sunday January 21, 2024 @05:55PM (#39083937)
In modern C++, you no longer need to manually-manage your memory (except when writing custom containers and low-level libraries). Memory is managed automagically, no garbage is generated and no collection is necessary.

Of course, you can also do manual allocations if you really wanted to, but - with the changes in the language since C++11 - you just don't have the motivation to do it.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pjmlp on Monday January 22, 2024 @03:48AM (#39087600)
Yet C++/WinRT uses a background deletion thread to overcome pauses in cascade deletions of COM instances.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by einpoklum on Tuesday January 23, 2024 @01:40PM (#39107642)
I wash my hands on any sort of MS Windows infrastructure...
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pyeri on Sunday January 21, 2024 @07:54AM (#39078016)
You don't need to go that far for GC's bad rep considering that excruciatingly slow Python can be found TODAY!
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by torginus on Sunday January 21, 2024 @08:13AM (#39078153)
Afaik (C)Python uses reference counting, it's slowness comes from the interpreter itself.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by _flux on Sunday January 21, 2024 @08:21AM (#39078192)
It uses also tracing GC to handle RC loops.

I guess doing it this way allows to have mostly deterministic collection (that is then just an implementation feature, not language semantics) while needing the actual tracing GC to not be that efficient, as it presumably needs to be executed less rarely.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by kaba0 on Sunday January 21, 2024 @10:52AM (#39079514)
Ref counting is a GC-algorithm, and the slowest at that (especially with multi-core sync, but that’s not the case with python), as a tradeoff for less memory consumption.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by DarkNova6 on Sunday January 21, 2024 @08:06AM (#39078099)
But you must understand, Python is safe and C is difficult. Therefore, to be fast we need Python (fast development that is because nobody _really_ cares about performance (or maintainability)).

If only more than two languages would exist!

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by h4ch1 on Sunday January 21, 2024 @10:44AM (#39079436)
> fast development that is because nobody _really_ cares about performance (or maintainability)

This is either

1. missing a /s

2. delusion

3. bait

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by tmtvl on Sunday January 21, 2024 @11:22AM (#39079850)
I believe it's 1, considering the statement 'If only more than two languages would exist!'. Granted, sarcasm doesn't transmit well in written text.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by amelius on Sunday January 21, 2024 @08:09AM (#39078125)
Python wasn't designed for speed.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by adev_ on Sunday January 21, 2024 @08:31AM (#39078266)
> You don't need to go that far for GC's bad rep considering that excruciatingly slow Python can be found TODAY!

To be fair, the GC is probably the last reason of Python speed problems.

Many languages also designed with GC performs significantly better than python in term of raw performance [^1].

The extremely dynamic nature of python associated with its reference semantics are probably significantly more to blame here.

[^1] https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pjmlp on Sunday January 21, 2024 @08:39AM (#39078326)
Another reason being that many people don't get GC theory, nor that because a language has some form of automatic resource management, does not mean the language doesn't offer other mechanisms.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by yxhuvud on Sunday January 21, 2024 @08:49AM (#39078396)
Another big reason is the lack of value types in languages like Java. Modern languages with a GC tend to have those, and where it makes sense to use them they help, a lot.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by amelius on Sunday January 21, 2024 @11:34AM (#39079948)
What are "value types"?
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Sunday January 21, 2024 @11:59AM (#39080202)
If you nest an object within another object you often want to embed the child directly in its parent, sharing the memory and avoiding the indirection that you get if you nest with a reference as is the typical approach with GC languages. Also embedding makes it clear that it's a 1:1 relation, i.e. non-optional, fixed identity etc.

AFAICT few GC languages allow you to do this, basically you have to buy into indirection and end up with webs of objects.

This is quite cache unfriendly, but the bigger issue for me is that it makes the code less clear and requires additional complexities since you can't just jump from a child to its parent by subtracting an offset from its address.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by ghusbands on Sunday January 21, 2024 @12:28PM (#39080473)
> makes the code less clear and requires additional complexities since you can't just jump from a child to its parent by subtracting an offset from its address.

Wait, so you're saying that code that subtracts an offset from a child node to get to a parent node is clearer and less complex than alternatives?

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Sunday January 21, 2024 @12:55PM (#39080772)
Not having the address relationship requires additional complexities. To get from the child to the parent, you need to spend an additional reference field, and need to keep it consistent with the other reference. If you embed directly, there's nothing in the relationship of the objects' identities that could ever get consistent. It's a strong guarantee.

How do you get from the child to the parent in, say Java? And how do you tell that a child is never swapped out?

How do you copy an object that holds, say 4 vec4, vec4 being a struct that itself 4 holds floats? With value types, say in C, it's 1 memcpy and you're done.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by ghusbands on Monday January 22, 2024 @06:58AM (#39088538)
In a particularly constrained and archaic language like C, it may be clearer. In a modern language, in no way is subtraction of an offset clearer and simpler than almost any alternative. Even in C, as you've mentioned elsewhere, you've had to use macros to make it at all clear, and macros can do anything and are inherently opaque.

Many other languages also have newer/different approaches to solve some of these problems, be they subclassing, generics, macros, JITs, or other. They mostly cannot do this as efficiently, but that seems less like a clarity/complexity concern and more like a low-level-programming concern.

> How do you get from the child to the parent in, say Java?

In Java, you do indeed have to embed mutual pointers and just be careful. As a C user, you must be used to being careful. Even C#, which does allow structs, doesn't have references-to-members that can be turned into references-to-owners. However, there are patterns and language features that people use to handle similar things, like subclassing (for lists) and generics.

> How do you copy an object that holds, say 4 vec4, vec4 being a struct that itself 4 holds floats?

Copying structs as a block works fine in Rust, C++ and C#, along with many other languages. Again, Java is a little more limited in this regard, though I believe they are working on adding value types.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Monday January 22, 2024 @02:22PM (#39094090)
I think we have quite different ideas what complex means. You seem to see a language (C or machine code), which, while based on simple principles, is complex in its behavior, especially if something goes wrong (which should not happen in the first place).

I see literally a subtraction operation versus a huge memory safe language framework set up over the same machine, plus a whole lot more user facing surface level source code, just to achieve the same thing.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by ghusbands on Monday January 22, 2024 @06:12PM (#39096901)
Sure, C and machine code can be simple (or simplistic) but in a world in which 70% of severe security vulnerabilities are caused by memory safety issues, I'll generally prefer languages that are safe against them, even if I can't then use text macros to get from a child pointer to a parent pointer. But that's off-topic, really.

In the message I originally replied to, I guess it's only the "since you can't ..." part that I really object to, as it's never going to be clearer to use &(par->child) and CONTAINER_OF(ch, some_type, child) than to use par.child and ch.parent.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by groestl on Sunday January 21, 2024 @12:49PM (#39080705)
> Wait, so you're saying that code that subtracts an offset from a child node to get to a parent node is clearer and less complex than alternatives?

Parent made me laugh out loud on this.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Sunday January 21, 2024 @12:58PM (#39080805)
I hope you've stopped laughing and can read and understand my answer.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by groestl on Sunday January 21, 2024 @01:14PM (#39080998)
Please, I did not want to offend you personally. It just took me by surprise. I understand your points, even though I'm with your direct reply, all things considered.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by jstimpfle on Sunday January 21, 2024 @05:35PM (#39083790)
The address offset subtraction thing specifically is used quite a bit in the Linux kernel for example. It allows to combine abstract code with concrete data. For example they define a red-black tree as a graph of just plain nodes. These nodes are totally abstract, they contain only node pointers but no useful data. The code is totally abstract, no need to instanciate anything a dozen times with different offsets and such. You simply wrap the abstract nodes with whatever concrete useful data you fancy.

The same approach works for lists and a variety of other data structures.

You can get from the abstract link node to the containing struct with a macro: CONTAINER_OF(ptr, containertype, membername). It's easy to use and unlikely to get it wrong.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by greesil on Sunday January 21, 2024 @11:51AM (#39080124)
In Java, primitives. int, boolean, float. Allocated on the stack, or the heap along with the object it is a part of.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pjmlp on Monday January 22, 2024 @03:46AM (#39087593)
Note about "modern languages with GC", this was already a thing in Common Lisp, Eiffel, Modula-2+, Modula-3, Mesa/Cedar, Oberon (and its linage),...

Java's mistake was ignoring them, as its was designed as set-top box programming language as Oak, pivoted to applets, and then pushed all over the place.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by foldr on Monday January 22, 2024 @05:05AM (#39087963)
The poster is talking about the subset of modern languages that have GC. They're not suggesting that only modern languages have GC.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pjmlp on Monday January 22, 2024 @08:04AM (#39089060)
> "Another big reason is the lack of value types in languages like Java. Modern languages with a GC tend to have those, and where it makes sense to use them they help, a lot."

Might be interpreted as older languages with GC did not had value types, which is bluntly false, going back to 1970's.

My remark was to make clear this isn't something new and modern, rather a design mistake in languages like Java, that is now trying really hard to fix it, while others designed after it (like C#), thankfully didn't follow the same trap.

How modern a 2001 language (C#), using ideas from Mesa/Cedar (1985), is an exercise in the semantics of "modern".

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by foldr on Monday January 22, 2024 @11:00AM (#39090889)
>Might be interpreted as older languages with GC did not had value types, which is bluntly false, going back to 1970's.

Ok, but you included Common Lisp in your list, which doesn't really have value types. (E.g. you cannot make an unboxed array of structs.)

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pjmlp on Monday January 22, 2024 @11:16AM (#39091189)
No, but you can have an array of primitive values, instead of an array of pointers.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by foldr on Monday January 22, 2024 @11:21AM (#39091258)
You can do that in Java too!
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pjmlp on Monday January 22, 2024 @11:25AM (#39091319)
Take your brownies, I guess, that wasn't my point.

As if me mis-remembering Common Lisp capabilities, invalidates the rest regarding "modern" GC languages.

Here is an array of structs in Oberon, 1987,

    TYPE
      Point = RECORD
        x, y : INTEGER
      END;

      Triagle = RECORD
        v1, v2, v3: Point
      END;

      Data = ARRAY 100 OF Triagle; (* static sized *)

      DynData  = ARRAY OF Triagle; (* dynamically sized *)

    VAR
       dynData : DynData; (* Allocated via NEW(dynData, elems)*)
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by foldr on Monday January 22, 2024 @11:42AM (#39091564)
No, it doesn't invalidate the rest of your comment. It just made it harder to figure out what point you were making in your original post (i.e. what the this referred to).

There's a little bit of irony here in how you react to people picking at details in your own posts, when your original post is precisely the same kind of pedantry!

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by rbehrends on Sunday January 21, 2024 @10:01AM (#39079021)
This needs some qualifications.

The above problem is about latency of stop the world collectors in a domain that requires extremely low latency. And if you think that stop the world collections are representative of garbage collection as a whole (i.e. the "bad rap"), this is just not being up to the state of the art. (It's just that generational/incremental collection is hard to impossible without having support for write barriers/read barriers/snapshotting on the compiler or hardware side, which makes that a practical no-go for a language that was never designed to have GC support.)

But in terms of throughput, the BDW GC actually performs pretty well, competitive with or beating malloc()/free() libraries. This is plenty enough for a number of applications, especially when it comes to batch processing. In fact, even the stop the world latency is (combined with parallel marking) plenty good enough for a number of types of regular GUI applications, where you don't have the fairly extreme latency requirements of standard video games.

It is also worth noting that manual deallocation (especially via RAII) isn't a panacea for latency, as that is just as prone to large pauses due to cascading deletes [1].

[1] While in theory you can do that lazily, in this case you're losing timeliness of deletion and may actually have worse worst case latency than a modern GC that can stagger its work to have bounded pause times. The benefit of RAII is that you may be able to plan these deletions, but even that can be surprisingly difficult at times, requiring extra management to keep data structures alive longer than normal. [2]

[2] Note that lazily deleting objects in RC to avoid pause times is not necessarily the answer; for one thing, you're introducing much of the complexity associated with incremental GC again (especially having to do X amount of deallocation work for each allocation), or risking considerable space overhead. https://dl.acm.org/doi/abs/10.1145/964001.964019 It also remains a difficult challenge when you're dealing with objects that aren't of bounded size (e.g. large arrays).

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by gumby on Sunday January 21, 2024 @12:20PM (#39080414)
> It's just that generational/incremental collection is hard to impossible without having support for write barriers/read barriers/snapshotting on the compiler or hardware side, which makes that a practical no-go for a language that was never designed to have GC support.

It was demonstrated in the mid 80s that the MMU could be used to implement the write barrier (when I saw that I knew lisp machines were a dead end, though I kept using them for as long as was feasible). You can use this and other compiler support to implement it in a language not designed for GC support, no problem.

The issue I think you meant is that you can’t have a transporting collector (which also compacts your working set, even allowing you to return memory to the system). A language like C++ doesn’t anticipate an object’s address ever changing, so that’s a no go.

I suppose you could write special shared_ptr / unique_ptr that supported address mutation but you’d need a compiler flag to check for an object’s address being taken… but to some degree the destructor paradigm renders a lot of this moot.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by rbehrends on Sunday January 21, 2024 @12:28PM (#39080483)
> It was demonstrated in the mid 80s that the MMU could be used to implement the write barrier (when I saw that I knew lisp machines were a dead end, though I kept using them for as long as was feasible). You can use this and other compiler support to implement it in a language not designed for GC support, no problem.

Yes, that's why I wrote about support "on the compiler or hardware side" (i.e. MMUs). That said, while this might work in theory, the BDW GC does have support for it, and in practice it doesn't actually work well. Throughput suffers and pause times can actually get worse.

By the way, another alternative way of having incremental collection without compiler support is to use fork() for snapshotting (there's an option in D for that), but that has its own issues, of course.

> The issue I think you meant is that you can’t have a transporting collector (which also compacts your working set, even allowing you to return memory to the system). A language like C++ doesn’t anticipate an object’s address ever changing, so that’s a no go.

No, I wasn't talking about a compacting collector. I very specifically meant generational and/or incremental collection.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by gumby on Sunday January 21, 2024 @01:49PM (#39081494)
> No, I wasn't talking about a compacting collector. I very specifically meant generational and/or incremental collection.

FWIW they are orthogonal

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by dataangel on Sunday January 21, 2024 @11:56AM (#39080177)
I have been writing low latency code for a decade and never seen cascading deletes be a problem. GC on the other hand is a constant latency problem for people.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by p_l on Sunday January 21, 2024 @12:27PM (#39080468)
running a throughput-oriented GC instead of latency/realtime one is a common error of those people (also, throughput oriented ones are usually the default)
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by rbehrends on Sunday January 21, 2024 @01:06PM (#39080892)
> I have been writing low latency code for a decade and never seen cascading deletes be a problem.

I don't know what your domain is, but the domains I'm familiar with (especially hard real-time) deal with the underlying constraints by way of restricting how you write programs. A side effect of these restrictions is that you generally avoid use constructs that give rise to cascading deletes. But ultimately, having to deal with these restrictions is suboptimal.

I remember a talk by Gil Tene (CTO and co-founder of Azul Systems) about how the problem with writing real-time Java was that it historically required you to write non-idiomatic Java code, which came at a serious cost to reuse and where he argued that one of the benefits of Azul's GC was that you could write (mostly) idiomatic Java and still have GC noise be less than OS noise.

There is of course the actual problem that the stricter your latency requirements are, the fewer GCs actually meet them. Plenty of modern off the shelf GCs meet typical soft real time requirements, but the harder your real time requirements get, the fewer implementations actually meet them (and are increasingly more expensive).

I'll also add that depending on how strict your latency requirements are, off the shelf allocators may not meet them, either, even for a single malloc() (though there are allocators that offer hard upper bounds for allocation costs, such as TLSF).

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by cplusplusfellow on Sunday January 21, 2024 @11:09AM (#39079704)
For all of the reasons you note above, this is why I've almost exclusively dealt with arena-style allocations of fixed-object-sizes when doing ultra low latency work.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by iainctduncan on Sunday January 21, 2024 @11:41AM (#39080034)
Hi, I'm just starting a (long) PhD in computer music languages, and one of my hoped-for projects is improving the GC for the Scheme implementation I work in for soft realtime use. If you (or anyone else) wouldn't mind sharing suggestion on resources for learning about low-latency modern GCs, it would be most appreciated. :-)
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by moonchild on Sunday January 21, 2024 @05:21PM (#39083686)
read the garbage collection handbook - https://gchandbook.org/
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by iainctduncan on Sunday January 21, 2024 @06:57PM (#39084376)
thanks, that's good to know. I'm working through his first GC book right now and plan to order the new edition of the gchandbook when I'm done the other (which I read was a gentler intro to the topic).

iain

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by pebal on Monday January 22, 2024 @05:04AM (#39087959)
You can look at the SGCL garbage collector for C++: https://github.com/pebal/sgcl. It works in a separate thread, is locks-free and never stops the world.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by iainctduncan on Monday January 22, 2024 @01:08PM (#39092982)
great, thanks!
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by zozbot234 on Sunday January 21, 2024 @12:58PM (#39080806)
The compiler support you need in practice is quite limited. There is an implementation of incremental cycle collection in Rust: https://github.com/chc4/samsara It's made possible because Rust can tell apart read-only and read-write references (except for references to interior mutable objects, but these are known to the compiler and references to them can be treated as read-write). This avoids a global stop-the-world for the entire program.

Cascading deletes are rare in practice, and if anything they are inherent to deterministic deletion, which is often a desirable property. When they're possible, one can often use arena allocation to avoid the issue altogether since arenas are managed as a single allocation.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by rbehrends on Sunday January 21, 2024 @01:16PM (#39081015)
> The compiler support you need in practice is quite limited.

This is true, but it's absent especially in C. Of course, as long as you can intercept writes and/or reads through pointers, you are good to go in principle. However, that solution may not be efficient.

> Cascading deletes are rare in practice

An array of objects (e.g. std::vector<std::string>) already has unbounded deallocation cost. People mostly think of tree-like structures here, but such structures only add the risk of stack blowout to the lack of an upper bound. But in principle, any container that does not have a size limit can give rise to unbounded pause times.

Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by torginus on Sunday January 21, 2024 @02:26PM (#39081971)
The problem isn't mark-and-sweep GCs it's that the Boehm GC is the Ford T model of garbage collectors.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by rbehrends on Sunday January 21, 2024 @03:10PM (#39082511)
Absolutely not. While it obviously should not be used for use cases that it isn't designed for, as a conservative mark-and-sweep GC it is extremely well engineered and has very good throughput.
Re:Boehm-Demers-Weiser conservative C/C++ Garbage Collector by ack_complete on Sunday January 21, 2024 @11:08PM (#39086080)
Sadly it was not just the GC, there were plenty of problems in Mono itself that adversely affected GC performance.

A significant one was a problem in the way that the Mono C# compiler generated foreach loops, which caused it to allocate an object for the enumerator that the regular .NET compiler was able to avoid. This caused foreach() to produce unnecessary garbage and resulted in a lot of Unity developers writing manual for() indexing loops instead of a more straightforward foreach() loop.

Another problem was a bug in the Mono standard library where one of the array containers -- I forget whether it was ArrayList or List<T> -- would fail to clear elements at the end on removals. This was innocuous for arithmetic types, but for reference types it would result in hidden entries in unused capacity holding onto stale references. In some cases this caused rather large trees of objects to persist unnecessarily, pinned invisibly by containers that had already been deleted from or were even empty.