Hence why it is usually one of the earliest chapters in any CS book about GC algorithms.
Reclaiming memory immediatly only works in simple data structures. Naive reference counting impletations have similar stop-the-world effects when releasing relatively big data structures, which can even lead to stack overflows, if the destructor calls happen to be nested.
In case of Objective-C and Swift, Objective-C tracing GC project failed due to the underlying C semantics, thus they took the 2nd best approach of enforcing Cocoa retain/release patterns via the compiler, which only applies to a small set of Objective-C data types.
Swift naturally had to support the same memory management model, as means to keep compatibility with the Objective-C runtime.
The fact is that Java isn't the only game in town, and all GC enabled system programming languages do offer multiple ways to manage memory.
Value types, traced GC memory references, global memory allocation, stack values, RAII, untraced memory references in unsafe code blocks.
Not every OOP language is Java, nor every GC is Java's GC.
Additionally, not every Java GC is like OpenJDK GC's, there are plenty to chose from, including soft real time ones for embedded deployments.
As for Android, it is a fork still catching up with what Java toolchains like PTC/Aonix are capable of, all because Google decided it could do better while screwing Sun in the process.
Since "GC-enabled system programming languages" is an oxymoron, a claim about what such languages may or may not include is just not very useful. But it's definitely the case that properly combining, e.g. "traced GC memory references" and RAII including deterministic deallocation for resources is still a matter of ongoing research, e.g. https://arxiv.org/abs/1803.02796 That may or may not pan out in the future, as may other things such as pluggable, lightweight GC for a subset of memory objects, etc., but let's stop putting lipstick on the pig that is obligate tracing GC.
- Mesa/Cedar at Xerox PARC
- Algol 68 at UK Navy computing center
- Modula-2+ at Olivetti DEC
- Modula-3 at Olivetti DEC/Compaq/HP and University of Washington
- Oberon, Oberon-2, Active Oberon, Oberon-07 at ETHZ
- Oberon-07 at Astrobe
- Component Pascal at Oberon microsystems AG
- Sing#, Dafny and System C# (M#) at Microsoft Research
- Java when running AOT compiled on bare metal embedded systems like PTC Perc and Aicas Jamaica
- D by Digital Mars
- Go at Google (Fuchsia) and MIT (Biscuit)
Lets stop pretending reference counting is the best of all GC algorithms, in spite the fact that is quite basic and does not scale in modern multi-core NUMA architectures.
The comment about "does not scale in multi-core NUMA" only applies if you have objects that are shared between threads because otherwise there's no atomics going on. For example, Rust has a generic ref-count mechanism that automatically uses atomic operations for ref-counts when an object might be shared between threads but otherwise does simple arithmetic. Non-atomic refcounts are most likely also going to be faster than any other global GC algorithm. Other languages require explicit differences but are still able to offer the same thing.
The fact of the matter is that the majority of objects do not require expensive GC of any kind & can live on the stack or have explicit ownership guarantees. Choosing defaults where everything might be shared is not a good default for systems languages as it pessimizes memory usage & CPU performance to a drastic degree.
That being said, GC does have its place in all manner of applications and has other advantages like making developers more productive which isn't a bad thing but these are domain-specific decisions. There are plenty of techniques - reference counting, memory pools, static memory allocation, various GC algorithms, etc, etc. Each has tradeoffs & every single GC system I've encountered means variable latency/stop-the-world and greedy memory usage (optimized for the 1 application). That's valid in some domains but certainly isn't desirable. If there were an awesome GC system like you claim that could perform that well it would have been deployed already to inemurable applications like all Java vendors, Javascript VMs, C#, etc, etc. It's an extremely complex problem.
Most of your links are niche commercial systems or even pure academic research systems. They're not proof of anything other than GC being possible to implement for various languages/machines which isn't a claim that's been disputed at all.
> Go at Google (Fuchsia)
AFAIK Fuchsia does not use Go for any systems-level portions. Those are written in C/C++/Rust last time I checked (with Rust being the official default going forward). Do you have any links to the contrary?
That sounds unduly broad. You really think the Linux kernel would be better off using a GC?
Reference counting can be better in terms of ease of implementation, cross-language interoperability, and by reclaiming memory immediately when the last reference to it disappears.