
A visual guide to the Go memory allocator from scratch - ngaut
https://blog.learngoprogramming.com/a-visual-guide-to-golang-memory-allocator-from-ground-up-e132258453ed
======
jfoutz
The last few days i've been struggling with how go decides heap vs stack.
Coming from a c/c++/java background where it's super clear, malloc or new goes
on the heap everything else goes on the stack, i've found go a little
frustrating. i still don't have a good sense of when the escape analysis will
fail and things get pushed to the heap.

This article isn't about any of that. This is much lower level, and will give
you insight about other languages approaches to growing addressable space. i
can't say i'm thrilled with the interleaved linked lists, but it's pretty neat
and works.

i don't write assembly, and i don't think real hard about how virtual address
space is managed. but maybe someday it'll be important and having read this
article some bells will ring. the article is cool and worth a few minutes of
your time.

 _edit_ interleaved linked lists isn't the right term. i don't think it's
_wrong_ but there's much more complexity with fitting the arenas. don't listen
to me, i'm a fool.

~~~
masklinn
> Coming from a c++ background where it's super clear, new goes on the heap
> everything else goes on the stack

AFAIK modern C++ practices eschew new/delete pretty completely, and while
std::unique_ptr or std::vector will create something on the stack it's a
glorified pointer, the actual data lives on the heap.

Also probably doesn't help with the specific criticism but FWIW the `-m` build
flag should print out heap escape. I don't know that there are editors which
integrate this though. And of course there are cases where you want the escape
and heap allocation, tough one possibility would be to ban escape analysis and
use `new` when you want to force a heap allocation, maybe?

edit: -m is pretty noisy though, lots of constructs will cause non-bypassable
escapes e.g. the fmt functions will "escape" their format string and every
single parameter:
[https://github.com/golang/go/issues/8618](https://github.com/golang/go/issues/8618)

~~~
jfoutz
happy to admit my c++ experience is very, very old. I totally understand that
things have changed. But even back in the day, libraries could do stuff that
hid 'new' from me. Heck, java libs will call 'new' all the time. the same goes
for c/malloc

I can cope with accepting a library that does god knows what. but my code, i
can see stack/heap split. perhaps it's a security blanket. perhaps it's
pointless.

this insight is actually really helpful. in some cases i care, in some cases i
turn a blind eye. maybe writing good go means i turn a blind eye all the time.
unless i need to inspect the escapes - which go provides good tools for. _chin
scratch_

Thanks.

~~~
masklinn
> happy to admit my c++ experience is very, very old. I totally understand
> that things have changed. But even back in the day, libraries could do stuff
> that hid 'new' from me. Heck, java libs will call 'new' all the time. the
> same goes for c/malloc

Yeah, Java necessarily `news` stuff, I believe it's the only way to
instantiate classes (ignoring factories).

~~~
jfoutz
Even factories. Java puts everything on the heap. There's no on the stack
object.

Java and go are both pass by value. Java makes it easy, because i know
everything is a pointer to a thing. I (unreasonably?) freak out about go
because i don't understand when an array backing a slice change. I'm just
chalking it up to me being old and dumb. Seems hard to track, but tons of
people do it, so the issue must be me.

~~~
pjmlp
Sure there is for primitive types, for objects the compiler gets to decide
what lands on the stack given escape analysis, until Project Panama finally
gets integrated.

Additionally both IBM and Azul JVMs do have extensions for stack allocations.

~~~
MrBuddyCasino
Exactly. Also unlike C++, allocation is nearly free on the JVM, and garbage
collection is cheap for short-lived ones.

------
sly010
Because of the way brk works it is not possible to have 2 different memory
allocators to use it in the same process.

Since malloc() in libc uses brk, no language with C bindings can use brk.

Does this mean basically most allocators other than libc malloc() use mmap()?

~~~
oddity
I'm surprised that anything still uses brk. Mentally, I've thrown it in the
same pile as fork or gets, but it's been a while since I've written a OS-level
memory allocator, so maybe my assumptions are incorrect.

~~~
zbentley
> Mentally, I've thrown it in the same pile as fork or gets

Why is fork included there? It's extremely useful in a wide variety of modern
applications. Or are you referring to specific libc functions rather than the
system call?

~~~
oddity
Comparing fork to gets is perhaps a bit unfair to fork. I was being lazy when
I tried to suggest a spectrum of deservedly rare api calls. :) It’s not broken
like gets or outdated like sbrk, but it doesn’t compose well with other parts
of the system and there are enough caveats that I recommend more use-case
targeted alternatives wherever possible.

For example: [http://www.evanjones.ca/fork-is-
dangerous.html](http://www.evanjones.ca/fork-is-dangerous.html)

