golang

golang

init 和 mian 函数

  • init 函数
    • 同一个 package 可以定义多个 init 方法
      • 同一个 package 不同文件 init 方法执行按照文件名先后顺序执行
    • 同一个 go 文件中可以重复定义 init 方法
      • 按定义顺序执行
    • 按照 import 顺序调用其他包的 init 函数
    • 导入顺序 mian -> A -> B -> C 则 init 执行的顺序正好相反
    • init 函数都在一个 goroutine 内执行
    • 执行完之后再执行 main 函数
      image.png

byte 和 rune 有什么区别

  • 都是字符类型, 都是别名类型
  • byte 本质是 uint8 类型的别名, 代表了 ASCII 码的一个字符
  • rune 本质是 int32 类型的别名, 代表了 UTF-8 字符

Go struct 能不能比较

  • 如果 struct 有不能比较的字段, 就不能比较
  • 只能比较是否相等, 不能比较大小
  • 所有属性都相等并且顺序一致的 struct 才能比较

goroutine 和线程的区别

  • 内存占用
    • goroutine 栈内存消耗为 2KB
    • Thread 消耗 1MB
  • 创建和销毁
    • Thread 创建和销毁都是操作系统内核级别的, 通常由线程池管理
    • goroutine 由 Go runtime 负责创建, 创建销毁消耗非常小, 是用户级
  • 切换
    • Thread 切换时, 需要保存各种寄存器
    • goroutine 切换只需要保存 3 个寄存器
      • PC 程序计数器
      • Stack Pointer 栈顶指针
      • BP 基址指针

slice 和数组的区别

  • slice 的底层数据结构是数组
  • 数组是定长的, slice 可以扩容
  • 数组就是一片连续的内存, slice 实际上是一个结构体, 包含长度, 容量, 底层数组
    1
    2
    3
    4
    5
    type slice struct{
    array unsafe.Pointer // 元素指针
    len int // 数组长度
    cap int // 容量
    }
  • 底层数据可以被多个 slice 指向, 所以对一个 slice 操作有可能影响其他 slice

map 实现原理

  • 数据被放入一个由桶组成的有序数组中, 每个桶最多可以存放 8 个 key/value
  • key 的 Hash 值低位用于在该数组中定位到桶, 高 8 位用于在桶中区分 key/value
  • 超了会链接到额外的溢出桶 overflow uintptr 所以数据结构为
    • hash 数组
    • 桶内 key-value 数组
    • 溢出的桶链表
  • 当 Hash 超过阈值需要扩容时, 会分配一个新的桶数组, 一般是旧的 2 倍
  • go 不会一次全量拷贝, 耗时太大, 会在每次读写 map 的时候动态迁移

为什么会 Hash 冲突

  • 通过哈希函数产生的哈希值是有限的, 数据可能比较多, 导致经过哈希函数处理后出现相同的哈希值

go map 并发导致 panic 如何解决

  • go 中 map 不支持并发读写
  • 使用 sync.map

go 的垃圾回收

  • 无分代
  • 不整理(回收过程中不对对象进行移动与整理)
  • 并发(与用户代码并发执行)
  • 三色标记清除法

golang
http://showyoubug.cn/2024/05/26/golang/
作者
Dong Su
发布于
2024年5月26日
许可协议