How Does Go garbage Collector Handle The closure Function?

auther: Nenad Ilić

Thank you for this video (and the whole series)!

I am currently learning Go as my first programming language using several other resources and I was happy to hear your take on closures (and also on interfaces). I haven't found the topic of higher-order functions well explained elsewhere, except, perhaps, on freeCodeCamp.org. From your video, I learned some new things.

I recently read an interesting article about Go's garbage collector (GC) and how keeping things on the heap is bad for performance. The article discussed how, because of that, and contrary to what many people say, pointers should be avoided if the performance is favored over memory, and even for the memory's sake. As I understood it, function stacks get destroyed immediately after the functions execute*, while everything kept on the heap remains for the time needed, even until the end of application.

Now, the thing is that Go compiler decides what is allocated to the stack and what to the heap at the compile time, often using the presence of pointers as a guide, so it is quite possible that even variables that look like they fulfill the criteria for stack allocation get their data allocated to the heap if the function that refers to them contains pointers. I also understood that checking the heap for garbage is slower than destroying the stacks. Don't take my words for granted, though.

(I can't find that same article again, but here are other two similar ones: this link and this link )

Anyway, that's why, in my Go exercises, which I come up with for practicing, I started defining anonymous functions inside the func main, in the top section, that I can comment as: "// here is a function section", when they have to deal with large data collections. These functions usually neither accept nor return anything, but rely on the variables declared above them, so I guess you can call them closures. For example: thisUsage := func() {something to do with the array members}. Or: var thisUsage func() was already declared at the top of func main in the declaration section, and then the function is defined as: thisUsage = func(){ something...}.

This replaced defining the same (named) functions at the package level, which would have to both accept and return an array or a struct, or at least accept a pointer to an array or a struct. All the variables that these anon. functions use are declared above the function section, so their scope is also the scope of these functions, but they don't need to be assigned any new values before the function definition.

Then, when needed in the code, after all the variables have their desired values, I simply call these anon. functions using the name of the variable to which such f-ion is assigned plus (). For instance, the line will read: thisUsage(). This obviates the use of pointers and might help in keeping the garbage collector happy to not find too many things on the heap.

This last is my guess. I don't actually know if Go compiler allocates the variables that live in the func main to the heap or to the stack, when they fulfill the criteria for the stack at the compile time. I would guess - stack.**

My intention was also to not cause copying of the variables between the functions, either, but since I am not familiar with the underlying mechanics of closures, I actually don't know if this solution achieves that goal. My hope is that variables having the scope of outer function (in this case: func main) are not copied, since they are visible to inner functions. It would surprise me if, under the scene, copies are made and given to an inner function (closure) and then back to the outer, calling, function, but that depends on how their internal mechanics is solved in Go. If I find about this mechanics, I will update this comment.

Anyhow, such functions are easier to write and the code looks cleaner. Even if I have a block of code that is used only once, I can still wrap it, i.e. make a function out of it that neither accepts nor returns anything, and shove it to the top, so when I look at the main code, I see a descriptive variable name invoking a call, instead of some long code, and thus I get the big picture easier to see.

I came up with this on my own, and I don't know if this is a common practice or not.

Here is a simple code example of mine: this link
--------- Update------
Compare the above code with these two variations, which use named functions and passing values and pointers, respectively: this link and this link
* Well, in the meantime I've learnt that a function stack (more precisely, its frame in the stack) doesn't get wiped out after that function's execution, but rather stays as it is until the next call of that function. Instead, that frame of memory is simply made inaccessible (invalid) between the execution and the next call. Hence, it never provides new free memory space for some other frame or allocation of another variable. However, the operation of invalidating that frame is very fast compared to garbage collection in the heap part of the memory: a link
** I did the so called ‘escape analysis’ on the simple example of code I gave above using the command: go build -gcflags="-m" in the command terminal, and that showed that the variables that are declared in the func main, and which are used by the anonymous functions within it (closures), do in fact remain on the stack. The only exceptions were the arguments to the functions from the ‘fmt’ package, i.e. Printf and Scanln functions. Also, the function literals remained on the stack, as well.