下面会给出网上收集的字节系 Golang 语言常见的面试题,按照热度排序哦

简述 slice 的底层原理,slice 和数组的区别是什么?

slice 是数组的引用,额外包括两个字段,长度 len 和容量 cap
slice支持扩容,本质上是再申请一块内存,将老数据复制过去,更新引用地址

简单介绍 GMP 模型以及该模型的优点  困难

简述 Golang 垃圾回收的机制  中等

Golang 采用的垃圾回收机制是三色标记法,分为白色(未标记)、灰色(标记中)、黑色(已标记)。
回收流程为:
1. STW,从根节点出发,将根节点标记为黑色,将能达到的所有节点标记为灰色,然后将所有能达到的子节点加入队列
2. 并发遍历队列中的节点,标记为黑色,且继续寻找其子节点标记为灰色并加入队列
3. 直到队列中所有可达节点均遍历完毕,那么剩下的白色节点就是不可达的节点,可以回收掉
在实际使用过程中,如果在标记过程中,节点指针被用户操作改变,可能会标记失败被错误的清除掉,因此 Go 又引入了写屏障

一次完整的 GC 分为四个阶段:

  • 标记准备(Mark Setup,需 STW),打开写屏障(Write Barrier),开启辅助 GC (mutator assist),统计 root 对象的任务数量
  • 使用三色标记法标记(Marking, 并发)
  • 标记结束(Mark Termination,需 STW),关闭写屏障。
  • 清理(Sweeping, 并发)

GC 调优

  1. 减少使用string类型中的 ‘+’(此种方式每次拼接都会申请一段新的内存空间),推荐使用 strings.Builder (类似切片的扩容机制)
  2. 小对象复用,尽量减少声明局部变量,小对象可以加入结构体来复用,方便 GC 扫描

协程与进程,线程的区别是什么?协程有什么优势?

Goroutines是可以同时运行的函数与方法。Goroutines 可以被认为是轻量级的线程。 与线程相比,创建 Goroutine 的开销很小。 Go应用程序同时运行数千个 Goroutine 是非常常见的做法。

  • 进程: 进程是具有一定独立功能的程序,进程是系统资源分配和调度的最小单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。
  • 线程: 线程是进程的一个实体,线程是内核态,而且是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
  • 协程: 协程是一种用户态的轻量级线程,协程的调度完全是由用户来控制的。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

简述 defer 的执行顺序  中等

1.

Golang 有哪些优缺点、错误处理有什么优缺点?

优点:

  1. 简洁、高效、安全
  2. 并发处理能力强
  3. 静态类型和编译型
  4. 丰富的标准库
  5. 跨平台和可移植性
  6. 强大的性能
  7. 垃圾回收机制
    劣势:
  8. 泛型编程支持不足
  9. 错误处理方式可能不同

采用错误返回方式,错误是一种内置类型,可以使用 error 类型来定义。而异常(panic)也可以通过 recover() 函数转换为 error来处理。优点是简单直观,一般与主体程序分离。可能的缺点是,需要在调用链中做好收集和处理,如果漏处理可能会有问题。

1
2
3
4
5
defer func() {  
if panic := recover(); panic != nil {
err = DumpStack(panic)
}
}()

两次 GC 周期重叠会引发什么问题,GC 触发机制是什么样的?  简单

Golang 的协程通信方式有哪些?  中等
channel 分为有缓冲和无缓冲,有缓冲的满不能存空不能取,都会阻塞;无缓冲的不存就不能取,阻塞
sync.waitgroup 控制协程完成时间,多用于等待一批协程完成
context 可以传值 context.withvalue;控制多个协程的生命周期,超时控制,取消信号等

△ 4次

简述 Golang 的伪抢占式调度  中等

△ 4次

什么是 goroutine 泄漏  简单

△ 4次

groutinue 什么时候会被挂起?  简单