5 ms·
> An important factor in reducing the size of the codebase and executable is that Jacobin relies on Go’s built-in memory management to perform garbage collectio
by ninkendo 3y ago
> An important factor in reducing the size of the codebase and executable is that Jacobin relies on Go’s built-in memory management to perform garbage collection, and so it contains no GC code.
This breaks my brain thinking about it. A lot of what the JVM does is interpreting/JITing bytecode and ensuring it links/executes correctly, and writing that logic itself in Go is one thing. But how does Go's GC help you garbage collect objects in the JVM you're implementing?
For example, you have objects in the JVM heap, tracked by the code you're writing in Go. You need to do a GC run. How does the Go GC know about the objects you're managing in the JVM? Do you just... write wrapper objects in Go around each of them, and code up a destructor so that freeing the Go object frees the tracked JVM object? How do you inform the Go VM about which pointers exist to your JVM objects?
I realize I'm in way out of my depth here, and only have a "user"'s understanding of what GC's do, having never implemented one myself, but it seems crazy to me that Go's GC can Just Work with a VM you're writing in Go itself.
- jsd1982 3y agoSince the VM controls allocation of Java objects, just implement the VM to allocate the Java objects into Go's heap using Go's native allocator thereby allowing the native Go GC to clean those up when they become unreferenced.
- ninkendo 3y agoHow would one allocate Java objects using Go’s allocator, as a program written in Go? Does go provide such primitives? Naively, something like: // Called when the hosted JVM code wants to allocate func makeJVMObject() (jObj, error) { var obj = new(jObj) // on go’s heap // do stuff return obj, nil } would make sense, except how do we keep track of who’s referencing it? JVM objects have fields which tell the GC how to crawl the object tree in the mark phase (and so do Go objects), but how do we make the Go GC aware of the fields the JVM knows about? A map maybe? Hmm, I guess a map could work… the jObj struct could have a map of fields it knows about, keys being the field name and values being where they point to… Now that I think of it this probably must be how all GC’s work, they can’t rely on static information to know the fields of each type they’ve compiled, it’s gotta be something like a map somewhere. I guess I may have answered my own question here.
- paulddraper 3y agoYep :) In fact, I would go so far as to say that it's harder to implement those without Go's GC just working. https://news.ycombinator.com/edit?id=37254746 https://news.ycombinator.com/edit?id=37254746
- erik_seaberg 3y agoMost languages have “precise garbage collectors” that always know from runtime type info which bits of an object are and are not heap pointers. Sometimes you see add-on “conservative garbage collectors” that have to assume any word might be a pointer if it looks like an aligned address in an allocated page. They can’t move objects to do compaction because they’re never sure which words are not pointers. Jacobin stores an object with a slice of its field values (each boxed as “any”) and types, so Go’s precise GC would be able to trace them: https://github.com/platypusguy/jacobin/blob/main/src/object/object.go https://github.com/platypusguy/jacobin/blob/main/src/object/...
- felixge 3y agoI suspect every JVM heap alloc is implemented by doing an alloc in Go. The JVM references to the object are pointers in the Go VM. So no special magic is needed. When the Go VM stops referencing an object, the Go GC will collect it.
- NovemberWhiskey 3y agoJava leans much more heavily on its GC than Go does so it will be interesting to see whether that's really an approach that works.
- starlevel003 3y agoGiven how primitive the Go GC is, I doubt it'll work at all.
- aardvark179 3y agoIt will work, bat since it’s not a moving GC you may end up with a lot of heap fragmentation, and as I don’t think it is generational it may get into a state where it stops collecting or has quite long pause times (can’t remember if it limits its pause times).
- suresk 3y agoIt is kind of interesting to look at some of the differences in GC approach in the JVM vs Go - the different goals, different tradeoffs, different approaches, etc. Go's is definitely simpler in that there is a single implementation, it doesn't have nearly as many tuning knobs, and it is focused on one things vs the JVM GC implementations that give you a lot of control (whether that is good or not..) over tuning knobs and it is a pretty explicit goal to support the different GC-related use cases (ie, low-latency vs long-running jobs where you only care about throughput). One of the things I really like about Go is that a lot of the designs and decisions, along with their rationales, are pretty well documented. Here are the GC docs, for example - https://go.dev/doc/gc-guide https://go.dev/doc/gc-guide. For example, Go doesn't move data on the heap around so to combat fragmentation, it breaks the heap up into a bunch of different arenas based on fixed sizes. So a 900 byte object goes into the 1K arena, etc. This wastes some heap space, but saves the overhead and complexity with moving data around.
- paulddraper 3y ago> it seems crazy to me that Go's GC can Just Work with a VM you're writing in Go itself. Far from it, it is more natural to do that than anything else. Simplified example: type Array struct { items *any[] } type Object struct { fields map[string]*any } These are the JVM values, and when the references to them disappear, the JVM values they reference can be GC'd as well.
- 38 3y agoyour example is not valid Go code: syntax error: unexpected ], expected type argument list and its also just poor style in general. "any" is already a pointer, so you would rarely design a pointer to any. example: https://godocs.io/encoding/json#Marshal https://godocs.io/encoding/json#Marshal
- earthboundkid 3y agoIt’s just pseudo code, relax. You’re not a compiler. You know what they meant.
- 38 3y ago[flagged]
- chc 3y agoWhat of it, though? I noticed, but didn't think much of it because pseudocode doesn't need to be valid and usually isn't. What is the problem with these syntax errors that you are trying to address by calling attention to them?
- MarkMarine 3y agoLighten up. Someone answered a question in a concise manner with some pseudo code, probably in a language they haven’t context switched to in a couple weeks. The pedantry you’re displaying doesn’t help the conversation. Do you have substantive insight to provide about how the go GC works with Java’s different JVM improvements? If not, you can just rate the post up or down
- bane 3y agoLeveraging the millions of man hours that goes into these run-time's subsystems is starting to become a "thing" I've noticed -- especially when running code not meant for them. For example, there's a Nintendo Switch emulator that I believe just uses the C# runtime's JIT instead of trying to roll their own. Lo and behold, it works and they've saved themselves thousands upon thousands of hours writing and debugging their own. It's kind of cool actually. I wonder if there's a future where somebody can just pick and choose language and runtime components parts to create the environment they want before even writing a line of code. We sort of do it a level lower with VMs and containers, and then pick and choose language features we want to use (e.g. C++), but I don't know of a good way to use Java's JVM, C#'s JIT, somebody else's memory profiler, another team's virtual memory subsystem etc. without writing a bunch of different pieces in different languages to get those benefits.