Hacker News new | past | comments | ask | show | jobs | submit login

Non programmer here, but would it make sense to add a keyword (or flag) to Go to manually allocate a piece of memory (ie not use GC). That way, for some use cases, you could use avoid GC for the critical path. Then when GC happened, it could be very fast as there would be far less to pause-and-scan (in this use case example). Obviously this would have to be optional and discouraged...but there seems to be no way to write an intensive real-time app with a GC based language. (again non-programmer that is writing this to learn more ;-)



There are two things you'd have to do at the same time that make this complicated:

- You'd have to ensure that your large data structure gets allocated entirely within the special region. That's simple enough if all you have is a big array, but it gets more complicated if you've got something like a map of strings. Each map cell and each string would need to get allocated in the special region, and all of the types involved would need new APIs to make that happen.

- You'd have to ensure that data structures in your special region never hold references to anything outside. Since the whole point of the region is that the GC doesn't scan it, nothing in the region will be able to keep anything outside the region alive. Any external references could easily become dangling pointers to freed memory, which is the sort of security vulnerability that GC itself was designed to prevent.

All of this is doable in theory, but it's sufficiently difficult, and it comes with sufficiently many downsides, that it makes more sense for a project with these performance needs to just use C or Rust or something.


> Since the whole point of the region is that the GC doesn't scan it, nothing in the region will be able to keep anything outside the region alive.

You can treat external references as GC roots.


How do you know that they exist, if you're not scanning that memory?


The data structure code can take care of this by registering GC roots with the garbage collector (and de-registering them if an external reference changes). It's no different in principle than any other smart pointer.


> You can treat external references as GC roots.

Which brings you back to doing an expensive scan of the large off-heap data structure you were trying to avoid.


Both of these requirements kinda remind me of Microsoft's Verona language.


I think the bigger problem with Go is a lack of GC options. Java, on the other end of the spectrum has multiple GC algorithms (i.e. the Z garbage collector, Shenandoah, Garbage-First/G1) each with tunables (max heap size, min heap size, for more see [1]). Java other issues, but it solves real business problems by having so many garbage collector tunables. Go's philosophy on the matter seems to be that the programmer shouldn't have to worry about such details (and GC tunables are hard to test). Which is great, until the programmer does have to worry about them.

[1] https://docs.oracle.com/javase/9/gctuning/garbage-first-garb...


> Java other issues, but it solves real business problems by having so many garbage collector tunables.

That real business problem is Java generates boat load of garbage so GC needs a lot more performance tuning to make application run normal.


Yes and no. You can get very clever by pre-allocating memory and ensuring it is never garbage collected, but at that point you're opening yourself up to new types of bugs and other performance issues as you try to scale your hack.

As you fight your language, you're GC avoidance system will become larger and larger. At some point you might re-evaluate your latency requirements, your architecture, and which are the right tools for the job.


Go has a tool for this job.

https://golang.org/pkg/sync/#Pool


checked in objects in a sync pool gets cleaned up on GC. It used to clean the whole pool, but now I think it does half each GC cycle. If you want to say "objects checked in should live here forever and not free themselves unless I want them to" sync pool is not the tool for the job.


Well, it's a start. In fact the existing interface lends itself really well to a rolling window on-demand (de)allocator, especially with that New function you can supply.

Just pool could've mitigated your problem at least partially, is what I'm saying.



i thought go has a GOGC=off option or something? did they remove it?



That would imply a drastic change to the language design. Essentially you are asking for 2 code generators (one for code managed by the go runtime and one managed by the programmer). It might be possible but it's most likely not gonna happen.


>would it make sense

Probably, yeah. But the Golang team would never add such a feature because of their philosophy of keeping the language simple.


GC isn't "slow" insofar as it's non deterministic. Modern garbage collectors are extremely fast, in fact.


Running every two minutes sounds pretty deterministic.


It was perhaps too deterministic. What's not mentioned in the blog is that after running for long enough, the cluster would line up it's GCs, and each node would do the 2 minute GC at exactly the same time causing bigger spikes as the entire cluster would degrade. I'm guessing all it takes is a few day night cycles combined with a spike in traffic to make all the nodes reset their forced GC timers to the same time.


Interesting, sounds like 2 minutes + random fuzz might avoid the thundering herd. Might be worth submitting a patch to the golang team!




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: