码农桃花源
  • README
  • channel
    • 06 - 从一个关闭的 channel 仍然能读出数据吗
    • 12 - channel 有哪些应用
    • 08 - 如何优雅地关闭 channel
    • 10 - channel 在什么情况下会引起资源泄漏
    • 00 - 什么是 CSP
    • channel 底层的数据结构是什么
    • 09 - channel 发送和接收元素的本质是什么
    • 11 - 关于 channel 的 happened-before 有哪些
    • 04 - 向 channel 发送数据的过程是怎样的
    • 03 - 从 channel 接收数据的过程是怎样的
    • 07 - 操作 channel 的情况总结
    • 05 - 关闭一个 channel 的过程是怎样的
  • map
    • map 的底层实现原理是什么
    • 可以边遍历边删除吗
    • map 的删除过程是怎样的
    • 可以对 map 的元素取地址吗
    • 如何比较两个 map 相等
    • 如何实现两种 get 操作
    • map 是线程安全的吗
    • map 的遍历过程是怎样的
    • map 中的 key 为什么是无序的
    • float 类型可以作为 map 的 key 吗
    • map 的赋值过程是怎样的
    • map 的扩容过程是怎样的
  • interface
    • iface 和 eface 的区别是什么
    • Go 接口与 C++ 接口有何异同
    • 如何用 interface 实现多态
    • 接口转换的原理
    • Go 语言与鸭子类型的关系
    • 值接收者和指针接收者的区别
    • 接口的构造过程是怎样的
    • 编译器自动检测类型是否实现接口
    • 类型转换和断言的区别
    • 接口的动态类型和动态值
  • 标准库
    • context
      • context.Value 的查找过程是怎样的
      • context 如何被取消
      • context 有什么作用
      • context 是什么
    • unsafe
      • 如何利用unsafe包修改私有成员
      • Go指针和unsafe.Pointer有什么区别
      • 如何实现字符串和byte切片的零拷贝转换
      • 如何利用unsafe获取slice&map的长度
  • goroutine 调度器
    • M 如何找工作
    • goroutine 调度时机有哪些
    • 什么是 go shceduler
    • goroutine 如何退出
    • 描述 scheduler 的初始化过程
    • 什么是workstealing
    • mian gorutine 如何创建
    • 什么是M:N模型
    • g0 栈何用户栈如何切换
    • schedule 循环如何运转
    • GPM 是什么
    • schedule 循环如何启动
    • sysmon 后台监控线程做了什么
    • goroutine和线程的区别
    • 一个调度相关的陷阱
  • 编译和链接
    • 逃逸分析是怎么进行的
    • GoRoot 和 GoPath 有什么用
    • Go 编译链接过程概述
    • Go 编译相关的命令详解
    • Go 程序启动过程是怎样的
  • 反射
    • Go 语言中反射有哪些应用
    • 什么情况下需要使用反射
    • 如何比较两个对象完全相同
    • Go 语言如何实现反射
    • 什么是反射
  • 数组和切片
    • 数组和切片有什么异同
    • 切片作为函数参数
    • 切片的容量是怎样增长的
  • GC
    • GC
Powered by GitBook
On this page

Was this helpful?

  1. map

map 的删除过程是怎样的

写操作底层的执行函数是 mapdelete:

func mapdelete(t *maptype, h *hmap, key unsafe.Pointer)

根据 key 类型的不同,删除操作会被优化成更具体的函数:

key 类型

删除

uint32

mapdelete_fast32(t maptype, h hmap, key uint32)

uint64

mapdelete_fast64(t maptype, h hmap, key uint64)

string

mapdelete_faststr(t maptype, h hmap, ky string)

当然,我们只关心 mapdelete 函数。它首先会检查 h.flags 标志,如果发现写标位是 1,直接 panic,因为这表明有其他协程同时在进行写操作。

计算 key 的哈希,找到落入的 bucket。检查此 map 如果正在扩容的过程中,直接触发一次搬迁操作。

删除操作同样是两层循环,核心还是找到 key 的具体位置。寻找过程都是类似的,在 bucket 中挨个 cell 寻找。

找到对应位置后,对 key 或者 value 进行“清零”操作:

// 对 key 清零
if t.indirectkey {
    *(*unsafe.Pointer)(k) = nil
} else {
    typedmemclr(t.key, k)
}

// 对 value 清零
if t.indirectvalue {
    *(*unsafe.Pointer)(v) = nil
} else {
    typedmemclr(t.elem, v)
}

最后,将 count 值减 1,将对应位置的 tophash 值置成 Empty。

这块源码同样比较简单,感兴起直接去看代码。

Previous可以边遍历边删除吗Next可以对 map 的元素取地址吗

Last updated 5 years ago

Was this helpful?