← Back to blogYouTube Video

Published October 22, 2025

Memory Management in Go - Part 2

Part 2 of 2 in Memory Management in Go

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

Summary

I break down how Go’s garbage collector works: it’s non-generational, concurrent, and uses a tricolor mark-and-sweep algorithm. I explain why Go skips generational collection — compiler optimizations keep most values on the stack, so the generational hypothesis buys little — and walk through mark-and-sweep: a brief stop-the-world at the start of marking to enable a write barrier, then concurrent tricolor marking where white means unused, blue means processing, and brown means in use, followed by sweeping away the still-white objects. I also cover the GOGC environment variable, which sets the heap growth target before the next GC cycle: default 100 means GC runs when heap memory doubles, 50 means it runs after 50% growth, and setting it to off disables GC entirely. My take is that the default is fine for most programs, but GOGC is there if you need to tune collection frequency.

Key takeaways

  • Treat Go’s GC as non-generational because compiler optimizations put most values on the stack, making generational collection less useful.
  • Expect a brief stop-the-world only at the start of marking to enable the write barrier; the rest of marking runs concurrently with your program.
  • Read the tricolor marks correctly: white = unused, blue = processing, brown = in use; anything still white after marking gets swept.
  • The GC only manages the heap; stack memory is handled automatically by Go.
  • Use GOGC to control collection frequency: default 100 runs GC when heap memory doubles; 50 runs it after 50% growth.
  • Avoid setting GOGC=off unless you have a specific reason; I don’t see a practical use case for disabling GC in normal programs.

Description

Learn how GoLang manages memory under the hood.

Transcript

Hey guys, welcome back to the Memory Management in Go video series. This is Part 2 of this series, and this is also the final part of this series. We're going to talk about how the Go Garbage Collector actually works, what sort of algorithms it uses, specifically how it manages the memory inside your Go program. So, without further ado, let's get started. Now, I'm going to put a bunch of fancy words on the screen over here. Golang uses a, first of all, it uses a non-generational garbage collector. I'll explain what all of these terms mean. It's also concurrent, and it's tricolor, and uses a mark and sweep algorithm. So that's a lot of words. Let's discuss every single one of them and see what each of them means. So these are basically the properties of the Go garbage collector. This is basically the kind of garbage collector that Go uses. First of all, let's talk about the non-generational part. So there's basically two kinds of garbage collectors. There's a generational garbage collector, and there's also a non-generational garbage collector. And the only difference in between both of these is that the generational garbage collector is going to divide your variables into two generations, two parts: the young and the old generations. So let me type that out as well over here. It's going to divide your variables into young and old generations. And what does that mean exactly? Well, basically, the generational hypothesis, the generational theory in garbage collection, is that the young variables, the variables that you declare right now, are going to be deleted much faster than old variables that have been stored, that have been used in the program for a long time. So basically, it's something like this. If I go in the main function over here, if I call this first function, or not even this, if I declare a function over here and just say something like, I don't know, `initDatabase`, right? This is going to declare a database and return that to me. Let's just say the database is just a DB variable, and it's just a string. Who cares, right? And it just returns that to us over here like this, right? And it's just going to return that DB. Okay, so this is obviously not a real database, but I'm just trying to give you guys an example. If we have a program over here, we obviously need to have a database connector over here as well, right? So I'm going to say `initDB` and store the database over here, right? And this database variable is probably going to be used throughout the program, right? Every time we want to fetch some data or we want to store or update some data, we need to use this database variable, right? So this is an old variable. This is probably going to be used for a very long time in the program, probably until the program ends, right? So the Go compiler is going to put this, or not the Go compiler, because Go does not use a generational garbage collector, but the generational garbage collectors are going to consider this an old variable because it is surviving for a very long time throughout the execution of the program. Similarly, or not similarly, but basically, if we have something like an add function over here, and this just takes two integers and returns the result. Let's say `sum = x + y`, and then `return sum`. There we go. This is a young variable. This is not going to be an old variable because this sum variable will be removed as soon as we return over here, right? It's not, it's not, it's not going to be used anymore after we execute this function and we return the result. So this is a young variable, and the generational hypothesis basically just says that the young variables, the variables that are declared right now, they're going to be cleared a lot faster, whereas the old variables, they're going to stay there for a very long time. They're going to keep getting used for a very long time. So the generational hypothesis, once it divides variables into young and old generations, next it's just going to query both of these generations and see which variables are still being used, right? And if one of the variables is not being used, it's going to clear them, right? It's going to delete the unused variables and free up that memory. Now, the point of dividing into young and old generations is this. As I said, the generational hypothesis considers that the young generation will clear up variables much faster. So it's going to query young generation more than the old generation, right? So, for instance, let's say it's going to query the young generation every one second. It's going to query the old generation every 20 seconds, right? There's a difference over there. And obviously, I'm using example intervals over there, example values. But the idea is it going to query the young generation much more than the old generation, right? If a generational garbage collector sees this DB variable and it sees that this is being used throughout the program and it not being unused, right, then it going to consider it an old variable, and it going to check this very, very rarely because this is part of the old generation now. Whereas something like this sum variable, it's part of the young generation because it is declared quickly and then also freed up soon after as well. So it's going to query this young generation a lot more. That's basically how a generational garbage collector works. The non-generational garbage collector is the complete opposite of that. It does not divide it, does not divide variables into generations. It just queries all of the variables without actually dividing them into generations and whatnot. And the reason the Go language uses a non-generational garbage collector is because there's a ton of different compiler optimizations inside Go, which basically just make this generational hypothesis completely pointless to use in Go. Because most of the Go variables are stored inside a stack. There's a ton of optimizations done in the Go compiler that allow us to store most values inside a stack. And you can go read about these optimizations on your own as well. I'm not going to discuss them in this video. It would just be too long. All right. But basically, the Go compiler allows us to store most variables inside the stack, which means that we don't really need this generational garbage collection, and we can just go with the non-generational garbage collection, which is a lot simpler because it does not divide into young and old generations. It's a lot simpler method of garbage collection, and Go is a very simple language, so they went with this. That's basically what the non-generational garbage collection means. Now, let's put this away somewhere. Concurrent. Concurrent garbage collection. This is very simple. This basically just means that the garbage collector is going to run alongside your program, all right? Like, it's not going to stop the execution of your program midway. It's going to run alongside your program simultaneously. So there's two types of garbage collectors. There's the concurrent type and there's the stop-the-world type. Stop-the-world garbage collectors are basically garbage collectors that are completely going to stop the execution of your program. So, as soon as the garbage collector runs, it's going to completely stop the execution of your program, pause it, run the garbage collection, free up some memory, and then resume the execution of your program. Those are stop-the-world garbage collectors, and as you can imagine, they're probably really bad because they're going to stop your program execution, and there's going to be delays and performance issues and stuff, right? Which is why Go uses a concurrent garbage collector, which basically will run right alongside your program. It's not going to stop your program in any way. So that's what a concurrent garbage collector means. Now, let's put this away somewhere as well. Let me just actually delete both of these. I don't think we need to keep them over here. There we go. So now let's talk about the tricolor and the mark-and-sweep algorithms. So before we talk about the tricolor algorithm, let's first talk about the mark-and-sweep algorithm because that is what uses the tricolor algorithm under the hood. And by the way, please also remember that this garbage collector only runs on the heap, right? The stack is automatically managed, as we talked about in the last video. There's no need to run a garbage collector in the stack because the stack automatically manages its memory, right? Garbage collection is only used in the heap. So let's talk about the mark-and-sweep algorithm. So this is basically the way in which Go, in which the Go garbage collector finds the unused variables and frees them up. So the way the mark-and-sweep algorithm works, it's going to stop the world, all right? Stop the world just means stop the execution of your program. And yes, I did say that this is a concurrent garbage collector, but just let me finish. First of all, it's going to stop the world, but only at the beginning of the marking phase, all right? This only runs at the beginning of the marking phase, and it runs so basically Go can set up the garbage collector state and also enable a write barrier on the memory in your program. So basically, this is going to ensure the correctness and the consistency of the program memory, right? Go is going to enable a write barrier, which this isn't going to prevent you from writing memory. It's just going to allow the garbage collector to know which new variables you're declaring, what new memory you're storing in your program, right? So that the garbage collector can also process that as well. Once this is done, it's going to start the world again and begin the marking phase, right? So this mark-and-sweep algorithm, it consists of two parts. First, it's going to run the marking phase and then the sweep phase, right? So here it's going to start the world and begin the marking phase. Now, the marking phase is where the tricolor algorithm is actually used. So let's add that as well. At this point, the garbage collector is basically going to use the tricolor algorithm to find unused objects in your heap memory, right? We know that the garbage collector only runs in the heap, so let me mention that over here as well. It's going to use the tricolor algorithm to find unused objects in your heap memory. Let me also show you a diagram of this. Let me draw something out over here. Let's go down over here and draw a bunch of circles. All right, so I have a bunch of circles over here and also a bunch of labels. Let's talk about how the tricolor algorithm works and how the Go garbage collector uses it to find the unused memory. So let's imagine that all of these circles, all of these nodes over here, are objects stored inside of our heap. What the Go compiler is going to do is it's first going to start processing up top at the root node, which in this case is A, right? Look at these colors as well over here. Look at these labels. First of all, it's going to color it blue, all right? So let me change the background over here to blue. There we go. And blue just means processing. The Go compiler, the Go garbage collector, is processing this root node. It's going to see which objects are still connected to it. So in this case, it's the B and the C variables. And since the garbage collector can see that this variable, that this object is still being used, it's just going to color it brown instead of blue because it knows that it's being used. Brown equals in use over here. Then it's going to process the B and C variables, which means it's going to color them blue as such. And then let's just say that the B object is connected to the D and E object, and the C object is connected to the F object over here, right? Now it's done processing these objects as well, and it's going to say that they are still currently in use. The program is still using these B and C objects. Then it's going to process the D, the E, and the F objects, which means it's going to color them blue. Blue means processing, right? There we go. And the F object as well. And as soon as it sees that all of these are still being used, it's just going to color them brown instead of blue. Brown means in use, right? The object is still being used. Now we still have these G and H objects, and they're not connected to the root node A over here, right? Which means that they are not being used anymore inside of this program, which means it's just going to color them white instead of black, as such. And I guess I should change the text color over here as well because this is hard to see. There we go. There we go. Awesome. So any object that is not being used, it's just going to be white, which just means unused. So that is the tricolor algorithm, right? It uses three colors. That is why it's called tricolor. And obviously, inside the memory, it's not going to obviously color objects where it's not going to fucking sprinkle some color on the objects. This is just what we call it to just represent it and just understand it better, right? But the actual objects inside memory, it's not going to give them a color, right? But anyway, that's just how we understand it. So just to give you guys a recap, every single object inside the heap, it's going to start off with the color of white, which means unused. Then the Go garbage collector is going to start at the root node, which in this case is A, process it, which will change its color to blue, and then see which nodes are connected to it, which objects are connected to it, and so on and so forth. As soon as it's finished processing a node, it's going to change that color from blue to brown, and it's just going to keep going down the chain until it runs out of nodes, right? At the end of that chain, whichever objects are completely unused, they will have never been processed, which means the Go garbage collector could never reach them. And since all objects are white by default in the beginning, and they only change to another color after they're done processing, that means that every single object that's still white at the end of this analysis, at the end of this tricolor marking algorithm, if they're still white, that means that they're unused, right? All objects start off with the white color, and then as they get processed by the garbage collector, the color changes, which means any object that's still white at the end of this tricolor phase is just going to be unused in memory, right? And so this is the marking phase, and it uses this tricolor algorithm to mark the unused and used objects inside your memory. Let's move this away and go back over here. So that's how the tricolor algorithm works to find unused objects in your heap memory. Once the mark and sweep algorithm has finished the marking phase and found the unused objects inside your memory, it's going to run the sweep phase, run sweep phase, which will basically delete all of the unused objects in the heap, right? All of the unused objects that are left in the heap, like such as this G and H variable over here, right? These are unused. They never got processed by the Go garbage collector. It could never reach them. And so this is going to get deleted in the sweep phase of the mark and sweep algorithm, and that is how the Go garbage collector is going to run it, what algorithms it's going to use, and how it's going to clear the memory and free up some memory inside your program. Now, finally, the last thing I want to talk about is the GOGC variable. Let me put this over here somewhere and change the text color to white. GOGC environment variable. There we go. Let me actually show you guys the documentation for this. So over here on the official Go website, in the runtime package definition, in the environment variables section, you can see this GOGC variable. And what this basically does is it sets the initial garbage collection target percentage. What that means is how much data, how much memory needs to increase since the previous garbage collection until the Go garbage collector is run again, right? So, a quick example over here. If you are, if the Go, let me zoom in as well. If your program is using, let's say, 5 MB memory, right? And the GOGC variable is set to 100%. That means that the Go garbage collector is going to run when your program memory reaches, let's say, 10 MB, right? Because the Go garbage collection percentage is set to 100%, which means the memory literally must double until the GC is run again, right? If instead I set the GOGC variable to, let's say, 50%, that means that the memory only needs to increase by 50% until the garbage collector is run again. So 50% of 5 MB is, I'm not good with numbers, but I think 7.5 MB. So as soon as your program uses 7.5 MB in memory, the garbage collector is going to run, right? If I set this to 200% instead, I guess that's going to be 15 MB. As soon as your program reaches 15 MB in memory, the garbage collector is going to run. So you can use this GOGC environment variable to basically go away, Google Drive, to basically tell the garbage collector when it should run, right? And you can basically optimize this as much as you want. I have never needed to optimize this all that much. I just go with the default value, which is 100. So basically, every time your program memory is going to double, the garbage collector is going to run. That's what I use. I just go with the default value. But if you're an advanced software engineer and you need to tweak this value, you have the option to do that by using this GOGC environment variable. This is basically how Go decides how often and when the garbage collector should run, right? We've already talked about how the garbage collector actually works, what it uses, all the algorithms and everything. And this GOGC variable is how it decides when to run, all right? And by the way, you can also set this to off. Like, you can literally set this variable to the string value of off, and if you say that, then the GC is just never going to run, right? If you set the GOGC variable to off, that means that the garbage collector is just never going to run. You basically turn off the garbage collection completely in the program, right? And personally, I don't know why you would ever do this. I don't see a use case for this, but there probably is, right? They gave you this option for a reason. But yeah, you can turn off garbage collection as well if you want to. I don't know why you would do that. I don't know what kind of programs you're writing if you do this, but yeah, you do have that option. So with that, we are done with this video series. We talked about how memory management works in Go. We talked about the kind of garbage collector that Go even uses. It's a non-generational, concurrent, tricolor mark and sweep algorithm using garbage collector. We talked about what all of those terms mean. We talked about the generational versus non-generational hypothesis, what the concurrent garbage collectors are like, what the stop-the-world garbage collectors are like. We also talked about the mark and sweep algorithm and how the tricolor marking works as well. And we talked about the GOGC environment variable over here and how that works as well. With that, we are done with this video series. I hope you learned how Go manages memory in its programs. It's actually a very fascinating topic. Like, I read about this a lot, and you guys know I want to learn as much as I can about the inner workings of these languages and inner workings of systems. I've been reading about this, and it is a very fascinating topic. Like, you read about all this, and you understand what different performance trade-offs these developers have to make in order to write these algorithms and use them, and all of the different design decisions they're going through in their minds to decide which algorithm, which method to use, which would be best, and so on and so forth. It's just a very fascinating topic. So I hope you guys learned something as well from all of this. And yeah, thank you so much for watching. Like, comment, subscribe, share the video, all of those wonderful things. I am actually late for class right now. I should be in university right now taking my classes, and I'm sitting home recording a video for you guys. So you're welcome. And yeah, I need to get going now. So see ya.

Share this article

Hassan Aziz pointing up

Dude, you’re at the bottom of my landing page.

Just book a call already if you’re that interested.

You scrolled all the way here.