9 ms·
Manual Memory Management in Go using jemalloc
- RcouF1uZ4gsC 6y agoThis actually sounds like the worst of both worlds. The number one feature of Go is simplicity. In service to that simplicity it deliberately left out a lot of features such as destructors and generics. And the thing is, the language works for its purposes. However, if you subvert that simplicity, it doesn't have the tools and abstractions to make using manual memory safer (destructors, generics, etc). My guess is you follow this path, you will be accumulating technical debt at a very high interest rate.
- LukeShu 6y ago> However, if you subvert that simplicity, it doesn't have ... destructors But it does have that, `runtime.SetFinalizer`. Sure it's clunky, and that's probably intentional: It's just there to be there as the escape hatch for you when you do need to subvert the normal way of doing things.
- earthboundkid 6y agoReposting my comment from when this was on Reddit: I'm confused about why you need jemalloc instead of just grabbing an N-gigabyte []Node and then manually making them "live" or "dead" by taking pointers. Or take a giant []byte and then cut that up into nodes with unsafe. Seems like those would be equivalent to jemalloc. Maybe throw in some runtime.KeepAlive to keep the GC from scanning it?
- BobbyJo 6y agoBecause then you have to actually implement the allocation logic.
- identity0 6y agoAllocation logic is much simpler than you think. A solution to a specific problem will always be simpler and faster than a general solution like jemalloc.
- eloff 6y agoYes? Allocation in a multithreaded program is simple? Balancing allocator space overhead, fragmentation, and allocator performance? What about getting statistics and insight into allocations? Detecting buffer overruns? You couldn't be more wrong. Behold the source code to jemalloc and despair. Allocation can be simple in very specific cases where you can use a single threaded arena.
- ayende 6y agoAllocation and deallocation in a perfomant manner, without introducing fragmentation, while being thread safe isn't easy by any means. Adds in the relevant taxes, such as detecting use after free, etc and that takes a LOT of work
- earthboundkid 6y agoThe solution in TFA doesn’t do anything about use after free, does it?
- WJW 6y agoThat is a logical fallacy. A solution for a specific _can_ be simpler and faster than a general solution, given enough time. However, jemalloc has had an absolutely huge amount of people-hours invested into optimizing it so it is not unlikely that it'll still be faster for specific problems unless the specific solution also has significant time invested into it.
- identity0 6y agoI have never seen a well-made but general solution beat a well-made and specific solution for one problem, in complexity or run time, ever. This is very true with allocators. A lot of the time people will just use 'malloc' without any thought into what they're actually allocating. For example, if you only allocate/deallocate from one thread, jemalloc is already way overblown in complexity.
- deleted 6y ago[deleted]
- chewxy 6y agoI think the idea is that so you have memory that is invisible to the Go GC. That way you are free (and at risk of memory leaks) to do whatever you want with that slab.
- mish15 6y agoYou can do this in pure Go though, you just need to manage the allocator yourself. That is a significant technical undertaking, but once done the advantages are huge. No GC overhead, no cgo. Done properly you can even have multiple readers and writers working concurrently in the same allocation space.
- chewxy 6y agoOK you piqued my curiosity. How?
- yencabulator 6y agomalloc isn't magic, just mmap some memory to dole out.
- mish15 6y agoYou just mmap memory as a slice. You can grow and shrink it, flush to disk if backed by a file, etc. In code it’s just a slice. Tough part is you need to allocate, control bounds, binary encode/decode, struct align, defrag, etc. It’s hard work, but the performance is 100% worth it if performance is your main goal.
- chewxy 6y agoTIL mmap'd memory is invisible to Go's GC
- scottlamb 6y agoThey did a great job of clearly laying out the caveats with this approach, which are extensive. It's obvious that they chose the wrong tool for the job and (un)fortunately were clever enough to make it fit. Go and Rust are both great languages. Rust is a much better language for this particular program.
- cle 6y agoHow do you know they chose the wrong tool for the job without more context into the decision making process and important factors/constraints at the time?
- shmerl 6y agoWhen you need to fight the garbage collector in a language that has one by design, it's a clear sign the wrong language was chosen, even if you'll find clever ways to fight it.
- cle 6y agoMy point is that, even if that is true, there are many other factors that go into technical decisions than pure technical merits. These decisions happen in the context of a business, with existing systems, codebases, teams of people with different experiences and preferences, unique market dynamics, etc. To say "you used the wrong tool for the job" without considering the conditions under which that tool was chosen isn't a productive assertion.
- shmerl 6y agoI've heard such argument before, and it's often misused to justify the choice of the wrong tool in my opinion, because it's not based on objective technical reasons. So it's easy to use it with vague logic of "there are some business needs".
- cle 6y agoAre you saying the non-technical reasons they considered weren’t valid? What were they?
- identity0 6y agoAt this point, why not just use C?
- ayush--s 6y agothat'd be rewrite
- secondcoming 6y agoThey've done the hard work already. It'd be trivial to port.
- pjmlp 6y agoUB, memory leaks, memory corruption, implicit conversions,... The benefit of using Go is keeping the memory safety for like 90% of the application, with just a tiny unsafe code portion. In C, 100% of the source code is unsafe.
- flohofwoe 6y agoAssuming that Go can easily call into C code you can still implement the performance-critical parts in carefully written and tested C and the other 90% in high-level Go. On the other hand, if implanting a faster allocator fixes performance problems, then there's something bigger amiss in the overall application design. Creating and destroying small objects at such a high frequency that memory management overhead becomes noticeable isn't a good idea in any case, GC or not.
- pjmlp 6y ago> performance-critical parts in carefully written and tested C Is something that not even the Linux kernel with its careful and throughout patch review process is not able to achieve.
- identity0 6y agoI believe calling C from Go is a massive pain, and is slow, because of goroutines. Go makes the OS syscalls directly to avoid going through libc.
- zelly 6y agoSomeone needs to implement Go in the JVM so it can finally have a good GC
- alexruf 6y agoWhat’s wrong with Go‘s GC. I think it’s actually pretty fast and gets better with each release.
- pjmlp 6y agoPlenty of stuff, https://github.com/golang/go/issues/42430 https://github.com/golang/go/issues/42430 As usual, Go knows better than other the older languages and then a kludge solution gets done.
- agnivade 6y agoIt seems to me like your opinion about Go GC is that it is an extremely buggy and slow piece of software. Every software has bugs. Whether those bugs are a major blocker for people to use them or not should be taken into account. The issue that you pointed out are difficult items which need more time and thought to take care of. But they aren't something which should cause any major pain in your day-to-day usage of Go. I would say as of 1.15, GC has improved by leaps and bounds and at this point, all major warts with the system are taken care of. But then again, I don't know in what context you are using Go. It may be the case that you have been affected by any of these bugs, and unless they get fixed, using Go is a blocker for you.
- WJW 6y agoIt's not particularly fast, for instance. The golang GC has pretty short pause times but its actual throughput in GB/s collected does not stand out. Short pause times are nice for interactive systems but don't matter as much for eg batch or background jobs, where total time to completion is much more important. The sister comment also has a link to a GH issue detailing many more specific flaws of the GC.
- kodablah 6y ago
- 02020202 6y agoa) making a db in gc language and then complaining about it and looking for weird fixes is just plain stupid b) Cgo should have never been made in the first place. it's wrong, period. c) drgaph folk broke badger on windows some time ago so i really do not care for them/it any more. d) cockroach's pebble also uses cgo for memory and it is utterly broken without cgo as well. these dumb mofos keep on repeating the same mistakes over and over and over again.
- pron 6y ago> In our experience, doing manual memory allocation and chasing potential memory leaks takes less effort than trying to optimize memory usage in a language with garbage collection They're generalising from the garbage collectors they know to all languages with garbage collectors. Go's GC is particularly crude, and great advances in GC technology have been made in recent years. E.g. take a look at the state of the G1 and ZGC collectors in OpenJDK 15/16.