Hacker News new | ask | show | jobs
by synergy20 638 days ago
Swift does not use virtual machine and garbage collection, it competes more to c++ and rust and if Apple is serious about pushing it cross platform that's definitely a welcome move, in fact, I can't wait even though I have never programmed in swift. the main point is that, it's memory safe, and seems much easier to code than rust.
7 comments

> garbage collection

Reference counting is garbage collection, and it performs significantly worse from a throughput perspective than tracing GC, which is possibly the most common metric for web server type workloads.

It really is not nitpicking, we should just really use tracing GC when we mean it.

There is kotlin native, which generates native code, using the same llvm that c++, rust and swift use. It doesn't have to use virtual machine, it is just one of targets.
not sure if it is 'production ready' and how does its performance/size go comparing to c++/rust/swift, in the end though, it's the ecosystem that matters.
> garbage collection

is reference counting not considered a form of garbage collection?

Nope; no having to pause execution and clean up. Miguel de Icaza (the creator of Mono) explicitly mentions this as one of Swift's key strengths over GC languages like C# during a talk about Swift at GodotCon 2023: https://www.youtube.com/watch?v=tzt36EGKEZo&t=7s&pp=ygURc3dp...
Miguel naturally wants to sell Swift for Godot story.

Also some the Mono issues were related that they never had Microsoft's budget for implementing a bleeding edge runtime.

From Computer Science point of view RC is and will stay a GC algorithm.

https://gchandbook.org/contents.html

https://sites.cs.ucsb.edu/~ckrintz/racelab/gc/papers/levanon...

https://sites.cs.ucsb.edu/~ckrintz/racelab/gc/papers/AzaPet-...

Maybe he should then read a book on garbage collectors that all start with ref counting..

Also, is it “pause execution and clean up” together? As ref counting obviously has to clean up, that’s the whole point - and it actually does so by blocking the mutator thread (the actual program written by the user). Then we didn’t even get to the point where syncing counters across threads are possibly the slowest primitive operation a CPU can do, so if we can’t know that an object will only ever be accessed from a single thread, ref counting has plenty shortcomings. Oh also, nulling the counter in case of a big object graph will pause execution for considerable amount of time (particularly noticeable in case of a c++ program exiting which uses a bunch of shared ptrs)

Perhaps? Most scenarios that explicitly involve .NET's GC vs Swift's ARC display much better performance of the former, to the point where the fact that ARC does not have GC pauses does not help if the whole things is multiple times slower, in many ways it's like Go's """low-pause""" GC design discussions that completely ignore allocation throttling and write barrier cost.

Swift lacking proper performant GC is a disadvantage. Upcoming features solve it by likely enabling more scenarios to sidestep ARC, but their impact on the Swift as a whole, and user applications that use them, is yet to be seen.

It's important to always remember - there's no free lunch.

I'm sad that Miguel de Icaza seems to have a bone to pick with C# nowadays, but it's not surprising given Xamarin story.

> Perhaps? Most scenarios that explicitly involve .NET's GC vs Swift's ARC display much better performance of the former

By which you mean "less CPU cycles on a desktop machine with plenty of memory"?

That's not when ARC is more performant; it's better on smaller devices that are under memory pressure and have swapped out some of your memory. In which case you have to swap it back in to go scan for pointers. And if you're a low-priority daemon then you evict higher priority pages in the process.

Perhaps? You assume GC takes unreasonably more space. It's purely a function of a tradeoff between running it more frequently, tuning heap sizing algortithms, choosing to run them as part of allocation calls on the same thread, sacrificing throughput in the process. GC can be more compact than what you assume. Modern good GC implementation are precise and don't have to mark dead GC roots as live, even within a scope of a single method. .NET and I assume Java GC implementations work this way - that's what "precise" means in "precise tracing GC".
It's not that it takes more space, it's that it has to read memory more often. Not all memory pages have the same cost to read.

Most memory swapping on most people's home computers is from web browsers for this reason; it's part that everyone uses them, but it's also because they're running JavaScript. And they're pretty well tuned, too.

Man the term must have changed since I was in school; i thought garbage collection was a much more general concept than a specific tactic to achieve this end of automatic memory collection. Pity, it was a useful term.

It's worth noting many others also consider automatic reference counting to be a form of gc, albeit one with different strengths and weaknesses than stack- and heap-scanning varieties

Memory safe and, with Swift 6, data race safe.
there is Kotlin Native - "Kotlin/Native is a technology for compiling Kotlin code to native binaries which can run without a virtual machine."

https://kotlinlang.org/docs/native-overview.html

> Swift does not use virtual machine and garbage collection, it competes more to c++ and rust

Doesn't it use ARC by default?

Which is reference counting, not garbage collection. Ref counts free when count = 0. Garbage collection scans all object pointers and looks for loops / no missing pointers.
That's tracing garbage collection. Reference counting is another type of garbage collection. https://en.wikipedia.org/wiki/Garbage_collection_(computer_s...
Reference counting is not tracing garbage collection. To also quote a Wikipedia Link: „The main advantage of the reference counting over tracing garbage collection is that objects are reclaimed as soon as they can no longer be referenced, and in an incremental fashion, without long pauses for collection cycles and with clearly defined lifetime of every object.“

+ https://en.wikipedia.org/wiki/Reference_counting

> Reference counting is not tracing garbage collection.

???

They didn't say it was.

Of course reference counting is not tracing garbage collection. I never said it was. The comment I replied to claimed reference counting was not garbage collection at all and seemed to think tracing garbage collection was the only kind of garbage collection. Reference counting and tracing garbage collection are two different types of garbage collection.
Reference counting is a kind of garbage collection.
it does, I thought ARC is more performant than GC and has no stop-the-world issue,thus not a GC
Usually, it's the other way around: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

binary-trees is almost completely dominated by the time spent in allocator code, and stresses its throughput. This benchmark showcases how big of a gap is between manual per-thread arenas, then tracing generational multi-heap GCs, then ARC and more specialized designs like Go GC. Honorable mention goes to BEAM which also showcases excellent throughput by having process-level independent GCs, in this case resembling the behavior of .NET's and OpenJDK GC implementations.

A tree is indeed a bad fit for RC; so is anything else where you have multiple references to something but know there is a single real owner.

I'd suggest keeping strong references to all the tree nodes in an array, then having everything within the tree be unowned. Basically fake arena allocation.

Actually, the way it's written:

https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

is a common way you see toy data structures code written, but it's inefficient (because pointer chasing is slow) and there's better patterns. If you use the arena method above, you could use indexes into the arena. If not, intrusive data structures (where the references are inside Node instead of inside Tree) are better.

Pointer chasing is irrelevant here. It takes <= 15% of the execution time, and CPUs have gotten good at it. If it takes more - it speaks more about the quality of the allocator which has poor memory locality. As noted in my previous comment, it is dominated by the time spent in the allocator/GC code.

Please read https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

The requirement to implement the same algorithm with the same data structure is what makes this benchmark interesting and informative. Don't tell me "allocate parent object A, allocate child objects C, D and E and assign them to A's fields, then allocate array F and G, and assign them to D's fields" isn't the bread and butter of all kinds of application logic, something that this benchmark stresses.

Some CPUs are good at it, but most aren't. (Apple's are.)

But that's not the actual issue; the issue is that pointers are big (8 bytes) and indexes are smaller, so now you can fit more in the cache. It would also help GC because it doesn't have to trace them.

Also, I don't recommend intrusive structures merely because they'd be better for language games. I think they're better in general ;)

ARC is a variation of GC. Besides, a tracing GC doesn't have to stop the world at all.
It has nowhere near the performance characteristics of those languages. It could, but it doesn’t. Look up a variety of language benchmarks. It’s typically ranked around Python/Javascript. You can get as fast as C but the code is very atypical.
There's no way it's close to Python. Where are the benchmarks?

https://github.com/sh3244/swift-vs-python

Shows a huge difference, as expected for a typed memory-safe compiled language using LLVM versus an interpreted language with a global interpreter lock.

The thread you just posted has a bunch of posts indicating this was not the actually the same program in Python and Swift; further, the Swift version was written poorly. Plus, the graph in the final post shows whatever Swift version someone ran tests on as much faster than Python.
It is slower, like probably ~3x but lets not exaggerate that it ranks around python

https://benchmarksgame-team.pages.debian.net/benchmarksgame/...