Golang 面试题

Golang 面试题

整理了一些面试题,关于go语言面试会考的东西,顺便整理自己的知识体系。

一、语言机制

  1. select是随机的还是顺序的?

先说答案,select会随机选择一个可用通道做收发操作。为什么呢?在源码中每一个select对应一个hselect结构,每个hselect结构下面都有个scase的数组记录每个case,在scase中记录着ch chan的结构也就是channel的结构pollorder将元素从新排列,scase就被乱序了。

2.Go语言局部变量分配在栈还是堆?

逃逸分析结果而定,Go语言编译器会自动决定把一个变量放在栈还是放在堆,编译器会做逃逸分析,当发现变量的作用域没有跑出函数范围,就可以在栈上,反之则必须分配在堆。

参考资料 : GO语言变量逃逸分析

3.Go语言逃逸分析有那集中场景?

  1. 指针逃逸 : 典型的逃逸case,函数返回局部变量的指针。
  2. 间接赋值 : 对某个引用类对象中的引用类成员进行赋值。Go 语言中的引用类数据类型有 func, interface, slice, map, chan, *Type(指针)。
  3. 栈空间不足逃逸 : 当对象大小超过的栈帧大小时(详见go内存分配),变量对象发生逃逸被分配到堆上。
  4. 闭包引用逃逸 : 外部函数引用内部函数变量,发生逃逸,分配到堆上。
  5. 动态类型逃逸 : 当对象不确定大小或者被作为不确定大小的参数时发生逃逸。
  6. 切片或map赋值 : 在给切片或者map赋值对象指针(与对象共享内存地址时),对象会逃逸到堆上。但赋值对象值或者返回对象值切片是不会发生逃逸的。

不要盲目使用变量的指针作为函数参数,虽然它会减少复制操作。但其实当参数为变量自身的时候,复制是在栈上完成的操作,开销远比变量逃逸后动态地在堆上分配内存少的多。

4.简述一下你对Go垃圾回收机制的理解?

v1.1 STW
v1.3 Mark STW, Sweep 并行
v1.5 三色标记法
v1.8 hybrid write barrier(混合写屏障:优化STW)

参考资料 : Go实时GC——三色算法理论与实践, Golang 垃圾回收剖析

5.简述一下golang的协程调度原理?

M(machine): 关联了一个内核线程。
P(processor): 代表了M所需的上下文环境,也是处理用户级代码逻辑的处理器。
G(goroutine): 调度系统的最基本单位goroutine,存储了goroutine的执行stack信息、goroutine状态以及goroutine的任务函数等。

参考资料 : Go并发原理

6.简单介绍下 golang 中 make 和 new 的区别?

  • new(T)是为一个 T 类型的新值分配空间, 并将此空间初始化为 T 的零值, 并返回这块内存空间的地址, 也就是 T 类型的指针 *T, 该指针指向 T 类型值占用的那块内存.
  • make(T)返回的是初始化之后的 T (引用类型本身), 且只能用于 slice, map, channel 三种类型. make(T, args) 返回初始化之后 T 类型的值, 且此新值并不是 T 类型的零值, 也不是 T 类型的指针 *T, 而是 T 类型值经过初始化之后的引用.

参考资料 : Go语言中new和make的区别

7.介绍下你平时都是怎么调试 golang 的 bug 以及性能问题的?

  1. panic 调用栈
  2. pprof
  3. 火焰图(配合压测)
  4. 使用go run -race或者go build -race来进行竞争检测
  5. 查看系统 磁盘IO/网络IO/内存占用/CPU 占用(配合压测)

8.如何获取 go 程序运行时的协程数量, gc 时间, 对象数, 堆栈信息?

调用接口runtime.ReadMemStats可以获取以上所有信息, 注意: 调用此接口会触发 STW(Stop The World)

9.介绍下 golang 的 runtime 机制?

runtime 负责管理任务调度,垃圾收集,以及运行环境。go提供了一些高级的功能,如goroutine, channel, 以及Garbage collection。这些高级功能需要一个runtime的支持. runtime和用户编译后的代码被linker静态链接起来,形成一个可执行文件。这个文件从操作系统角度来说是一个user space的独立的可执行文件。 从运行的角度来说,这个文件由2部分组成,一部分是用户的代码,另一部分就是runtime。runtime通过接口函数调用来管理goroutine, channel及其他一些高级的功能。从用户代码发起的调用操作系统API的调用都会被runtime拦截并处理。

Go runtime的一个重要的组成部分是goroutine scheduler。他负责追踪,调度每个goroutine运行,实际上是从应用程序的process所属的thread pool中分配一个thread来执行这个goroutine。因此,和java虚拟机中的Java thread和OS thread映射概念类似,每个goroutine只有分配到一个OS thread才能运行。

10.goroutine池是否像其他语言中的线程池一样有意义?

视情况而定,调度程序中的状态成本可以忽略不计,但是goroutine保持的状态重新创建的成本可能很高。后一点可用作将goroutine保留在池中的理由。但是,另一方面,在大多数情况下,将执行类似任务的goroutine的资源组池化(而不是goroutine本身)更容易。

参考资料 : Does a goroutine pool make sense like thread pools in other languages?

# ,

评论

`
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×