golang gc

步骤:

暂停所有任务执行

启动mark(mark这部分还是要把原程序停下来的

mark完成后就马上就重新启动被暂停的任务

sweep任务和普通协程任务一样并行

和其他任务一起执行 如果运行在多核处理器上,go会试图将gc任务放到单独的核心上运行而尽量不影响业务代码的执行

go team自己的说法是减少了50%-70%的暂停时间

优化目的:

基本算法: 清扫+回收 Golang gc优化的核心就是尽量使得STW(Stop The World)的时间越来越短

 

三色标记法:

1. 程序创建的对象都是白色的

2. 扫描开始,扫描所有可达对象, 标记为灰色

3. 从灰色对象中找到其引用对象,标记为灰色, 标记为灰色后把自身标记为黑色

4. 监控对象中的内存修改,并持续上一步的操作, 知道灰色标记的对象不负存在, 此时回收白色对象

5. 将所有黑色对象变为白色,并重复以上所有过程

 

标记-清除(mark and sweep)算法的STW(stop the world)操作,就是runtime把所有的线程全部冻结掉,

所有的线程全部冻结意味着用户逻辑是暂停的。这样所有的对象都不会被修改了,这时候去扫描是绝对安全的。

 

标记和清除算法包含两种逻辑:

标记: 

清除:

标记完成后, 只剩下黑白两种对象, 黑色对象是程序恢复后直接使用的对象, 如果不触碰黑色对象只触碰白色对象, 是不影响清除的 所以清除逻辑和用户逻辑可以并行

 

 

标记过程可以并行吗? 

通俗的讲:就是在gc跑的过程中,可以监控对象的内存修改,并对对象进行重新标记。(实际上也是超短暂的stw,然后对对象进行标记)

 

延伸: golang的内存管理

How do I know whether a variable is allocated on the heap or the stack?

From a correctness standpoint, you don’t need to know. Each variable in Go exists as long as there are references to it. The storage location chosen by the implementation is irrelevant to the semantics of the language.

The storage location does have an effect on writing efficient programs. When possible, the Go compilers will allocate variables that are local to a function in that function’s stack frame. However, if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must allocate the variable on the garbage-collected heap to avoid dangling pointer errors. Also, if a local variable is very large, it might make more sense to store it on the heap rather than the stack.

In the current compilers, if a variable has its address taken, that variable is a candidate for allocation on the heap. However, a basic escape analysis recognizes some cases when such variables will not live past the return from the function and can reside on the stack.

 

如何得知变量是分配在栈(stack)上还是堆(heap)上?

准确地说,你并不需要知道。Golang 中的变量只要被引用就一直会存活,存储在堆上还是栈上由内部实现决定而和具体的语法没有关系。

知道变量的存储位置确实和效率编程有关系。如果可能,Golang 编译器会将函数的局部变量分配到函数栈帧(stack frame)上。然而,如果编译器不能确保变量在函数 return 之后不再被引用,编译器就会将变量分配到堆上。而且,如果一个局部变量非常大,那么它也应该被分配到堆上而不是栈上。

当前情况下,如果一个变量被取地址,那么它就有可能被分配到堆上。然而,还要对这些变量做逃逸分析,如果函数 return 之后,变量不再被引用,则将其分配到栈上。

 

 

 

 

 

参考文档:

https://juejin.im/post/5c8525666fb9a049ea39c3e6

http://legendtkl.com/2017/04/02/golang-alloc/

https://blog.csdn.net/K346K346/article/details/80849966 

 

posted @ 2019-06-30 12:04  hao.ma  阅读(209)  评论(0编辑  收藏  举报