Golang QA
简单描述下三色标记法。
三色标记法基于标记清除的 gc 方法,初始化所有的节点为白色,然后从 root 开始扫描,引用到的节点为灰色,然后再从灰色节点扫描,并将灰色变为黑色节点,重复扫描灰色节点直到灰色节点消失,就只剩下白色和黑色节点,清除掉白色节点。
golang 是如何优化 stw 的?
golang没有根本解决stw,只是通过并行执行标记和清除过程缩短stw的时间。
stw 在 gc 过程中怎么触发的?
gc中有两个阶段触发了 stw。第一次是在 gc 初始化的时候,启用 gc 辅助功能和写屏障。第二次是在re-scan 中,即第一次扫描完成,在进行第二次扫描新引用的节点时。
什么是写屏障?
写屏障是用来在 gc 扫描的过程中,如果有新的节点被引用,那么会在引用的过程中记录下来,通知 gc,然后 gc 就不会漏掉新的被引用节点了。
局部变量分配在栈还是堆上?
默认是分配在栈上的,但是如果变量存在逃逸分析,那么就必须分配到堆上。
defer 的执行顺序。
如果有多个defer,执行顺序是后进先出。也就是说 defer A;defer B;那么会先执行B,再执行A。
defer 和 return 的执行顺序。
首先,return 不是一个原子操作,分为revl = xx;retu revl,defer的执行顺序在这两个原子操作之间,也就是revl=xx;defer xx;retu revl。
string 和 nil。
string 是不能赋值为 nil 的,不过有个小技巧,可以使用 *string 设置为 nil 。
逃逸分析
逃逸分析是指判断一个变量有没有脱离原来的作用域被引用,如果没有,变量的存储就是在栈上,否则就必须存储在堆上。众所周知,go 1.13 提升了 defer 30% 的性能,这个提升其实就是根据逃逸分析优化的,更少地在堆上存储提升性能。
make 和 new 的区别
普通的变量声明,都会默认赋予零值,并且可以直接修改,例如 var i int
。但是对于引用类型 var i *int
,在进行修改的时候就会直接** panic 无效的内存地址**,可见声明之后并没有给指向的变量分配内存。因此就需要new
和 make
出场了,两者都是用来初始化内存的,但是 new 初始化并赋予零值,返回变量的地址。make 则只适用于 channel、slice、map,因为这三者本身就是引用类型,初始化为非零值且返回对象的值而不是地址。
程序初始化顺序
从 main 函数开始,首先初始化 import, 循环深入到导入包的内部,依次初始化 import、全局变量、init 函数,然后依次返回,最后返回到 main 函数。
goroutine 是不是抢占式
是,有专门一个 M,叫做 sysmon,用来监控线程。当一个 goroutine 运行超过 10ms,sysmon 就会发起抢占式请求。
GPM 模型简述
G goroutine,P Process 线程,M machine 系统线程。
M 从 P 的运行队列中取出 G 运行,当 P 的运行队列为空,则会从 Global 队列中取,若 Global 队列为空,则会去其他的 P 的运行队列中取。
当 G 遇到 channel 或者 I/O 操作阻塞后,则会被放到对应 P 的等待队列中。
P 的数量是由 GOMAXPROCS 指定。
CSP 和 Actor 模型
两者都是并发的处理模型,Actor 模型中 actor 是主体,actor 之间传递消息不需要中介,并且是异步的。golang 实现的 CSP 则是通过 channel 来进行消息传递,并且是同步的。
Tags: Golang