Understanding The Memory Model Of Golang : Part 2

In part 1 of this series, I shared my love for Golang and motivation for these series of stories. In this story, I will share the lessons I learnt from the first 8 minutes in the video.

The Classical Memory Model

Yes, I shamelessly cropped this image from the video

The image above depicts the classical memory model used in many programming languages. When your program is loaded into memory, the following 3 sections are created in memory for specific purposes :

Constants & Instructions

This section of memory contains the program instructions together with constants / static contents. It’s usually small and its size is determined at compile time.

The Heap

This section (which isn’t an actual implementation of a Heap you know from your Computer Science class) has an elastic capacity (ie, grows and shrink at runtime), limited by the system, hold pointers, arrays, and other data structures. All the memory heavy-liftings happen on the heap.

The Stack

The stack section of memory represents the state of execution. It is composed of stack frames that hold function calls and their associated local variables. A stack frame is added (technically, pushed) onto the stack anytime a function is called. And anytime a function returns, a stack frame is removed (technically, popped) from the stack.

Now, here comes the interesting part and why I think Golang proudly sticks out like a sore thumb among the rest. You see, Golang was created to address the needs of modern-day software engineering and the environments within which languages such as C, C++, Java were created to function have passed long ago. Today, it is not surprising to see machines with 64 or even 128 cores and there’s the ever increasing need to build systems that efficiently use all the computing resources available on these machines. Therefore, the classical memory model as presented above can’t work for modern-day engineering and hence, there was the need for the creators of Go to deviate from the norm.

Evidently, from the classical model, it is obvious that (1) Having one stack meant there could be one-and-only-one state of execution since the stacks primary work is to represent the state of execution. This meant that, there will be challenges for multi-threading (2) In the classical model, stacks have predefined sizes (eg. 8MB). This isn’t a very good use of memory. If you called too many functions (especially through recursions) then you’ll be welcomed by the cold hands of the dreadful stackoverflow error. They should be dynamically sized as the need arises. (3) To support concurrency, the entire classical memory model needs to be duplicated many times. It is this duplication that presents the difficulties of crafting multi-threaded applications because of shared memory.

How Being Different Paid Off In Golang

Yes, I did it again even more shamelessly!

As I stated in Part 1, Golang isn’t afraid to be different. There are times the creators had to sacrifice even convenience for safety. In Go’s memory model, the following deviations were proudly made :

  1. One heap, and one section for constants and instructions
  2. One stack per goroutine (To support the representation of the multiple states of execution needed for modern-day concurrency and parallelism)
  3. Elastic / Dynamic stacks that borrow memory from the heap. And, because the heap is limited by the system, in effect, the number of stacks is also limited by the system. Also, because these stacks don’t have predefined sizes, they make judicious use of memory and allow for tens and hundreds of thousands of goroutines to be started even on a moderately packed computing system.

In my honest opinion, this is a very smart move and has allowed easy concurrency in Golang. Because, there’s a stack per goroutine (including the main function in your code), concurrent running operations don’t communicate by sharing memory. Rather, they share memory by communicating through synchronised channels thereby avoiding race conditions and other difficulties that abound in concurrent programming.

As promised, I will write more stories until we’ve covered everything in this video :

In the meantime, don’t forget to subscribe to my Go Rapidly Channel on Youtube where I will soon be publishing all the awesome video tutorials I have personally recorded to freely share my experience and love for Golang.

Thanks for your time!