Hacker News new | ask | show | jobs
by neonsunset 638 days ago
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".
1 comments

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.

> it's that it has to read memory more often

Wait until you learn about "reads become writes with ARC" :)

ARC as implemented by Swift, on top of ObjCs retain and release, is design that has an advantage in being more simple, but at the same time worse at other key aspects like throughput, contention, memory traffic and sometimes even memory efficiency. Originally, Swift was meant to use GC, but this failed because Apple could not integrate it well enough with existing Objective-C code, leading to a very crash-prone solution.

Also, JavaScript has nothing to do with the lower in abstraction languages discussed in this chain of comments.

You're lecturing me about my job here. I don't need to learn nothin'.

> reads become writes with ARC

That's not a big problem (it is a problem but a smaller one) since you can choose a different tradeoff wrt whether you keep the reference counting info on the same page or not. There's other allocator metadata with the same issue though.

A more interesting one comes up with GC too; if you're freeing all the time, everyone compresses their swap these days, which means zeroing the freed allocations is suddenly worth it because it compresses so much better.

> Originally, Swift was meant to use GC, but this failed because Apple could not integrate it well enough with existing Objective-C code, leading to a very crash-prone solution.

It was Objective-C that had the GC (a nice compacting one too) and it failed mostly for that reason, but has not come back because of the performance issues I mentioned.

> Also, JavaScript has nothing to do with the lower in abstraction languages discussed in this chain of comments.

Oh, people definitely want to use it in the same places and will if you don't stop them. See how everyone's writing apps in Electron now.

> A more interesting one comes up with GC too; if you're freeing all the time, everyone compresses their swap these days, which means zeroing the freed allocations is suddenly worth it because it compresses so much better.

Moving GCs solve it much more elegantly, in my opinion, and Java is just so far ahead in this category than anyone else (like, literally the whole academic field is just Java GCs) that not mentioning it is a sin.

> literally the whole academic field is just Java GCs

Not necessarily a good thing. While reading Java-related papers I found myself constantly thinking "damn, they wrote a paper for something that is just 2.5 smaller pull-requests in dotnet/runtime". I wouldn't put the modern state of academia as the shining example...

What are you even talking about? C# has a famously simplistic GC which is basically one big, 1000 lines file. C# has very different tradeoffs compared to java, it pushes complexity to the user, making their runtime simple. Java does the reverse, having the language very simple, but the runtime is just eons ahead everything else. Like, call me when any other platform has a moving GC that stops the world for less than a millisecond independent of heap size like ZGC. Or just a regular GC that has a similar throughput as G1.
If your point of reference are Objective-C and Swift only, and you have not looked at how .NET's or Go's (which makes very different tradeoffs w.r.t. small memory footprint) GCs work, it might be interesting to re-examine prior assumptions in light of modern designs (I can't say Go is modern per se, but it is interesting nonetheless).

Also, .NET tends to heavily zero memory in general, as the spec dictates that fields, variables, arrays contents, etc. must be initialized to their default values before use (which is zero). Compiler can and will elide unneeded zeroing where it can see, but the point is that .NET's heaps should compress quite well (and this seems to be the case on M-series devices).

There are popular apps written in C# on the platform, but they're Unity games, which use il2cpp and I believe still use Boehm gc. I think this demonstrates a different point, since even a bad GC apparently doesn't stop them from shipping a mobile game… but it is a bad GC.

(Games typically don't care about power efficiency much, as long as the phone can keep up rendering speed anyway.)

> Also, .NET tends to heavily zero memory in general, as the spec dictates that fields, variables, arrays contents, etc. must be initialized to their default values before use (which is zero).

Same for most other languages, but there's a time difference between zeroing on free and zeroing on allocation. Of course, once you've freed everything on the page there are ways to zero the page without swapping it back in. (just tell the OS to zero it next time it reads it)

Yeah, Unity has terrible GC, even with incremental per-frame collection improvement. It's going to be interesting to look at the difference once they finish migration to CoreCLR.

If you'd like to look at a complex project, you can try Ryujinx: https://www.ryujinx.org. It even has native integration[0] with Apple Hypervisor to run certain games as-is on ARM64 Macs. There's also Metal back-end in the works.

Other than that, any new .NET application runs on MacOS provided they don't use platform-specific libraries (either something that uses Linux dependencies or kernel APIs or Windows ones). My daily drive device is an MBP.

A side-note is that on MacOS .NET does not use regions-based heaps yet and uses older segment-based ones. This has implications in terms of worse memory usage efficiency but nothing world-ending.

[0]: https://github.com/Ryujinx/Ryujinx/tree/73f985d27ca0c85f053e...