Skip to content

Golang QA #17

Description

@snxq

简单描述下三色标记法。

三色标记法基于标记清除的 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 来进行消息传递,并且是同步的。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions