记录面试准备和面试过程中的学习(二) go

179 阅读4分钟

数据结构

线程安全: 线程安全就是内存安全,线程共享堆空间,对相同空间访问会产生并发问题,go里面部分的结构是线程安全的,但也有不是的。

切片:即动态数组,切片在运行时可以用data,len,caps(指向连续内存区域的指针,长度,容量),类似vector,引用类型,不可比较。扩容会导致新申请内存拷贝。可能的陷阱,切片用一大片数据初始化,最后用到的很少,但是因为少部分的被引用导致该部分内存无法回收。将用到的部分新建切片。

map: 哈希,拉链法,桶大小为8,装载因子已经超过 6.5,哈希使用了太多溢出桶会导致哈希扩容,增加更多的桶,线程不安全。

sync.map 线程安全的map,read,dirty两个map(存指针),read为缓存,misses记录缓存未命中的次数,每个value有expunged和nil。先从read找,再dirty,未命中,misses+1。具体实现复杂,另起一文。

channel:环形队列,双指针

编译

  1. 词法分析:字符流转变为Token序列,有限自动机形式。
  2. 文法: LALR(1),建立抽象语法树
  3. 类型检查: 静态类型检查,运行期引入类型信息,对接口转变为具体类型进行动态类型检查,错误会程序崩溃。处理OTARRAY检查右节点,处理哈希检查键值类型,make分支检验
  4. 中间代码生成
  5. 机器码生成

内存管理

基础:线性分配,链表分配(首次适应,最优适应等)

内存分配器:根据申请大小分为微对象(16B),小对象(32KB),大对象,绝大多数对象再32KB以下。内存分为线程缓存,中心缓存,页堆。32KB以上直接从页堆分配,小对象先线程缓存再中心缓存。

堆空间

  1. 1.10版本 连续内存空间

image.png spans 区域存储了指向内存管理单元 runtime.mspan 的指针,每个内存单元会管理几页的内存空间,每页大小为 8KB;

bitmap 用于标识 arena 区域中的那些地址保存了对象,位图中的每个字节都会表示堆区中的 32 字节是否空闲;

arena 区域是真正的堆区,运行时会将 8KB 看做一页,这些内存页中存储了所有在堆上初始化的对象;

  1. 1.11 稀疏内存

image.png

地址空间的状态

  1. None:内存未被保留或映射
  2. Reserved 运行时持有,但不能访问
  3. prepared内存被保留,但一般没有对应物理页
  4. ready可以安全访问

更具体另起一文

GC

从堆,goroutine中收集根对象标记为灰色,标记灰色对象引用的也为灰色,所有引用对象都被标记后标记为黑色,全部结束后清除未被标记的白色。GC程序是单独的,所以会有因为程序运行导致白色对象被引用不该被清除的问题。早版本GC时停止程序,现在会屏障保护删除、添加的节点(标记为灰色)。

栈内存管理

逃逸分析,分析指针作用域,决定变量的分配位置。

  1. 指向栈对象的指针不能存存货在堆中

  2. 指向栈对象的指针不能在栈对象回收后存活

  3. 构建带权重的有向图,其中顶点 cmd/compile/internal/gc.EscLocation 表示被分配的变量,边 cmd/compile/internal/gc.EscEdge 表示变量之间的分配关系,权重表示寻址和取地址的次数

  4. 遍历对象分配图并查找违反两条不变性的变量分配关系,如果堆上的变量指向了栈上的变量,那么该变量需要分配在堆上

  5. 记录从函数的调用参数到堆以及返回值的数据流,增强函数参数的逃逸分析

连续栈和分段栈

csp

channel:环形队列实现,现如先出,goroutine之间通信

context:上下文,同步截至时间,取消信号,数据。