Back to blogYouTube Video

Published October 20, 2025

Memory Management in Go - Part 1

Can't play the video or having issues? Here's the direct link.

AI Summary

This video provides a deep dive into how the Go programming language manages memory, focusing on the distinction between the stack and the heap and the mechanism the compiler uses to decide where data is stored.

Key Takeaways

  • **Memory Management Importance**: Without proper management (allocating and freeing memory), programs can suffer from memory leaks and eventually crash due to system memory overflow.
  • **Comparison of Approaches**: - *Manual (C/C++)*: High control but prone to human error and bugs. - *Ownership Model (Rust)*: Compiler-enforced manual management that prevents memory issues. - *Garbage Collection (Go, Python, JS)*: Automatic management where a garbage collector (GC) identifies and frees unused data.
  • **The Stack vs. The Heap**: - **The Stack**: Stores local variables. It follows a Last-In-First-Out (LIFO) structure. It is extremely fast, automatically managed as functions return, and does not require the GC. - **The Heap**: Stores complex objects and variables that must persist beyond the lifetime of a single function. It is slower than the stack and requires the GC to clean up unused memory.

Description

Learn how GoLang manages memory under the hood. LINKS Website: https://www.hassandev.me My Book: https://www.hassandev.me/designing-websites X / Twitter: https://x.com/nothassanaziz

Transcript

Auto-generated transcript
Hey guys, what's up? How is everybody? It's been so long since I sat down to record a video because my university opened up and I just have classes all the time and I just can't find the time to sit down and record a video until now. Through some miracle by God, I found some extra spare time that I can use right now to record a video and that's what we're gonna do. In this video, I'm going to teach you how memory management works in Golang. So you guys know I'm learning Go and building all sorts of projects in it. We recently finished building the Redis clone in Go and yeah I'm learning as much as I can about this language and in this video I'm going to be teaching you how memory works inside Go. So this is going to be a two-part video because there is a lot of stuff we need to cover. I'm going to go very deep into this topic and so like this is not going to be a high level overview. We are literally going to go very deep into this topic and study the inner workings of how memory is managed in Go. And so we need to divide this video into two parts. So let's get started. First of all, I just want to talk about why memory management is even important. So why is memory management important? And by the way, as you guys can see, I am using this website called Excalidraw for building these, I guess, presentations live, just so it's easier for you guys to understand what I'm saying, right? Because rather than me just saying things, you can also see the text over here and everything else and I guess that makes it easier to learn. Anyway, why is memory management important? Well, because when you're writing a program, you're obviously going to be declaring variables, storing data inside those variables and just processing that data and so on and so forth, right? So you need access to the system memory so you can store that data. Now, if you just keep storing and keep adding more and more data into the memory without actually clearing it, right, without actually deleting the unused data, then over time the memory is just going to overflow, right? You're just going to run out of system memory and your program is going to crash, right? Obviously. So we need some sort of method or approach to manage the memory that our program is using, right? We need it so we can allocate more memory to store more data we needed so we can free up some memory used by previous unused data and so on and so forth right now different languages manage memory differently right so we have something like i guess c or c plus plus where you have to manually manage your memory right so you have to so you have to basically just allocate and free up memory by yourself right you have to manually do this and this can be very cumbersome because you have to manually do it you have to manually remember to free up any memory after you're done using some variable in something right and a lot of times you can just forget to do that right we're humans so manual memory management in c and c++ is prone to a lot of bugs right like just google something like c memory leaks and you'll find i don't know hundreds thousands of cases literally thousands of cases where this issue arises so then you also have languages like Rust which are gaining a lot of popularity and they are also like Rust is also kind of a manual memory management. Now the way Rust handles memory management is it does something called the ownership model which is kind of still manual right because you're still manually managing the memory but but the difference is that this ownership model will basically let the compiler handle all of the memory for you in that as soon as you're done using a variable it will automatically clear it and no sooner and no later than that right I'm not going to go into too much detail about the ownership model but it is kind of manual in that you need to write your programs in a way that rusts compiler will be satisfied right the ownership model in the rust compiler will be satisfied but it is still an improvement over C and C++ because when you use rust and when you use the ownership model of rust you basically cannot have any memory issues at all right and then there's also languages like go python javascript typescript all of these other scripting languages that use a garbage collector so i'll say garbage collection over here now garbage collection is probably the easiest way to manage memory in your program because all it really does is you just write your programs as normal and this garbage collector will run on its own and it will basically just check which variables which data is still in use and it'll just leave those there and the data that you're not using the variables that are unused it'll just free them up in memory it'll delete them and free up the memory that is used by them so this garbage collection is the automatic way to manage memory and it also what Go uses So that what we going to talk about Now we learned that Go uses a garbage collector to manage memory but let's go one level deeper. How exactly does Go represent memory in its programs? Because look, memory at the most fundamental level is just a bunch of RAM chips inside your computer, right inside your CPU. Just a bunch of RAM chips attached to your motherboard, right? How does that, how does Go represent that in its programs? So the way it does that is it basically uses two memory structures, two data structures called, one of them is the stack, all right, and the other one, I'll put it over here, is the heap. So let's talk about what both of these are and how they work. And let me just change the text color as well because I don't like blue over here. All right, so let's talk about the stack first. The stack is the simplest data structure to understand out of these two. So we'll start with that. Now the stack is used to store local variables declared in functions. All right. So let me show you a quick example over here. I have this file over here called stack.go and has a bunch of functions first, second, and third and fourth. And they just each call the next function. Right. So for instance, if I call the first function and the first function declares some variables like x equals one, right and y equals 2 this is going to be stored on the stack all right if I do the same thing in the second and the third functions it's going to be stored on the stack because these are local variables to the functions a stack is basically like a stack of plates right so if I draw something like that over here like something like this right you have a bunch of plates on top of it right? You can think of every single plate over here as a function, right? You call one function, it's going to declare some variables, store some data, and all of that will be stored on the stack. You call the next function, it's going to do the same thing. You call the next function after that, it's going to do the same thing. And then as soon as the execution of this function is over, all of the variables declared in this stack frame are going to be wiped out, all right? So, for instance, if I call the first function, it calls the second function, then the third, and then the fourth right and then over here in the fourth function if i have a variable called something like x over here right as soon as this fourth function has been finished executing this x variable is going to be completely removed from memory all right so that's how the stack works you basically have a stack of functions where every single piece in the stack stores the data inside that function and then as soon as the function is finished executing all of the data inside that function will be will be wiped out by the way this nil pointer dereference we don't need to worry about that right now that we're going to cover that in just a bit but just understand that a stack is like a stack of plates where each plate is a function call and every time the function finishes executing all of the data inside that function all of the entire the entire stack frame is just wiped out all right it's just wiped out just like that so that's how memory management works inside the stack you can see that it's very like automatic we don't need a garbage collector to manage memory inside the stack so let's let's write all that down right automatically manage doesn't need a garbage collector and also it's super fast like if you're storing data inside the stack it's going to be very very fast to store and retrieve data because it's just going to be at the top of the stack right whatever function you're using over here like whatever function is being called if you're running the fourth function we know that whatever data we store over here is going to be at the top of the stack and we can just retrieve it quickly right when we want to clear data from the stack we know that as soon as this function finishes executing we just need to remove the top element in the stack right and then we go back to the third function we do the same thing then in the second we do the same thing and back in the first we do the same thing and it's just super fast and super easy to manage memory on the stack i can also um just remove all of these variables go back to main.go and by the way you can ignore all of this this is just some unrelated code uh if i run the first function in the stack over here you'll also see a stack frame so let me run this and you probably know what all of this is you've probably seen this in other languages as well. This is a stack frame and what this stack frame basically tells us is where the program started executing which functions it called and where it failed right. So you can see that it first started by calling the main function over here then the first second third and fourth and the fourth function is where the program crashed right because of this nil points or dereference error that we placed over here right so this is what you can kind of think of as a stack right every single function over here is one more element inside the stack as soon as the function finishes executing we remove it from the stack and all of the data inside that function is wiped out right and so that's how the stack works. Now let's talk about the heap because the heap is where garbage collection actually happens. So the heap is, let me type that out over here as well, the heap is much slower than the stack and it uses a garbage collector to clear memory. And the way that objects are stored in the heap is basically you store the object data inside the heap and then store a pointer to that object inside the stack all right and let me just there we go yeah so basically when you try to store data inside the heap or actually when go decides to do that because you don't manually do it go does it for you when go stores an object inside the heap it's basically storing that object inside some random place in memory and it returns a pointer to that object which it stores on the stack on the stack of whatever function you're currently executing right now you're probably wondering because we've discussed the differences between stack and heap and we know how memory is managed on both now you're probably wondering how does go decide when to store a variable on the stack or on the heap and basically there's a couple of rules that go uses and those rules are called escape analysis all right so let's place that over here as well call it escape analysis and basically escape analysis is just a bunch of rules that the go compiler runs on every single function every single piece of data to decide whether it escapes that function if it escapes it if it escapes that function then it's going to store it on the heap it's going to store that object on the heap and if that object does not escape the function then it's going to store that on the stack so simple variables like um you know x equals 5 or something y equals i don't know 10 15 these are very simple variables and they're not going to escape the function right we're not going to be using these variables as soon as this first function has finished executing right and so they're not going to escape the function and they're going to be stored on the stack all right now i have a bunch of different examples of escape analysis rules over here and we can go through each of them right now So basically a stack uses the lefo data structure. Lefo. Last in, first out. So the last element that was added in will be the first one to leave out. Basically, every time you run a function, it's going to create a new stack frame and everything, right? It's going to run all of these functions over here. It's going to go to the fourth function. This is the function that was last in, right? This is the last function that we're running. and so this will be the first function that we throw out right because as soon as this finishes executing we're going to throw its stack frame out and then this third one and then the second one and then so on right so the stack is a last in first out data structure whereas the heap is a lot more random right there's no like order in how elements are stored or removed inside the heap stack is an ordered data structure heap is not so let's go through each of these rules one by one first of all very simple if you're returning a pointer to a value then that value is escaping and it must live on the heap because look in this foo function over here where and let me just zoom in as well that's probably easier for you guys to see uh i guess that's enough in this foo function over here we're returning a pointer to an integer right we're declaring an integer and we're returning a pointer to it now even though after this function is finished the x variable is not really needed anymore we're still returning a pointer to that x variable and we need to store x on the heap because if we don't if we store x on the stack it's just going to get cleared right it's going to get deleted as soon as this function is finished executing and then this pointer that points to the x variable will be invalid right And go does not allow invalid pointers, right? So values must be stored on the heap if you are using a pointer to them. If you're returning a pointer to a value, it must be stored on the heap, right? Because x is escaping and the value of x is still being used by this pointer even after this function has finished executing So that the first example If you returning a pointer or using a pointer to a value then the value must be stored on the heap Secondly if you returning complex objects or if you using complex objects in your code such as a map, a slice, or a struct, then all of these are going to be stored on the heap. Every single one of them. Maps are stored on the heap, slices are stored on the heap, this user struct, any struct is going to be stored on the heap even if it's just a super simple struct like this user struct where all we really store is a name it's still going to be stored on the heap now moving on here we have a counter function and it returns another function which references a value in the outer function so basically in the counter function here we declare a variable x then we return a function that uses that value x right x is declared in the counter function not in this sub function over here that we return right and so if we return this function let me just show you uh quickly over here let's say f will be the function and we run the counter function over here uh like this there we go this is going to return a function that returns an integer right there we go since this inner function is using the x variable that is declared up here in the counter x is escaping and it must live on the heap because once the execution of this counter function ends x will be removed and then this function will be invalid because it's trying to use an invalid x variable over here right which is why x is escaping which is why it must live on the heap so if you're using an inner function that is referencing outer function values like this x variable over here then this x variable cannot be stored on the stack it must be stored on the heap so it outlives this function right now moving on from that as well i guess this is the final example that we need to show so any objects that you store inside a complex object like a slice a map a struct etc are going to be stored on the heap themselves as well so here we have a slice of integers we have an x variable and we append it to the um to the slice when we do this x is going to escape the stack and live on the heap because the slice itself is also going to live on the heap similar to this other example up here where we create a new user struct right since user is stored on the heap this name field this name string is also going to be stored on the heap because it is part of a complex object a struct over here that is stored on the heap all right so these are a bunch of rules about escape analysis and how go the go compiler decides which objects to store on the stack and which objects to store on the heap. It basically runs all of these rules on every single variable that you declare in your code and it decides does this value escape the function that is calling it, that is storing it, or does it not escape that function. If it does escape it's going to store it on the heap, otherwise it's going to store it on the stack. And remember the stack is a much faster data structure, it's automatically managed, it does not need a garbage collector. The heap is the complete opposite of that. It's kind of fast still, but it's a lot slower than the stack. It does need a garbage collector. So there is a performance overhead of using a garbage collector and it just kind of slows down your program a little bit. And if you're building really performance critical or speed critical programs, then you're going to have to pay a lot of attention to this topic. But anyway, we talked about memory management in Go. We talked about how Go manages memory through garbage collection. We talked about the two different data structures that Go uses, the stack and the heap, to manage memory. And we also talked about escape analysis and the rules of escape analysis that the Go compiler uses to decide which variables to store on the heap and which to store on the stack. This was part one of this two-part video on memory management in Go. In the second part of this video series, I guess, It's not even a series. It's just a two-part video. But in the second part, we're going to talk about how the garbage collector in Go actually works. So how the Go garbage collector actually works. We're going to talk about how it runs, when it runs, what kind of algorithms it uses to find the unused memory, find a used memory, and so on and so forth, right? How the garbage collector actually processes every single variable, all of the data inside your program, and how it decides which to throw out, which to keep, and so on and so forth. We're going to discuss all of the algorithms and the methods and everything that the garbage collector uses in the next part of this video. But for now, we're done with this. Thank you so much for watching. Like, comment, subscribe, share, all of those wonderful things. And I will see you in the next video where we will discuss how the Go compiler or the Go garbage collector actually works.

Share this article

All great things started with a conversation

If you've got a cool project or opportunity and you want me to be a part of it, set up a free meeting with me here, and let's talk. 😊