golang的内存模型
memory model
heppens-before的概念
内存重排
为了读写内存的效率,会对读写指令进行重新排列,这是cpu重排。 还有编译器重排:
x = 0
for i in range(100):
x = 1
fmt.Println(x)
编译器优化后
x = 1
for i in range(100):
fmt.Println(x)
但是一旦x被别的goroutine修改,就会无法出现预期的结果。
CPU为了抚平内核、内存和硬盘之间的读写速度差异,使用多级缓存。
因此对于多线程的程序,CPU提供锁机制,即内存屏障,memory barrier,要求所有到cache line中的操作都要立马刷到内存中去,对于多核cpu还有mesi 缓存一致性协议去保障。
copy-on-write
写入时复制(英语:Copy-on-write,简称COW)是一种计算机程序设计领域的优化策略。其核心思想是,如果有多个调用者(callers)同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的(transparently)。此作法主要的优点是如果调用者没有修改该资源,就不会有副本(private copy)被建立,因此多个调用者只是读取操作时可以共享同一份资源。
- redis如何实现bgsave
- redis单线程,现在双线程(1 网络 1 工作)
- fork进程, 地址空间和父亲一样,两个进程指向同一个地址空间,新老不影响,当父子进程中有更改段的行为发生时,再为子进程相应的段分配地址空间,copy-on-write
- 热门数据会产生全局的热点,全查一个key redis会被打死
- 缓存到内存中
- 这个更新怎么办,后台goroutine定期去查询,更新,更新时可以使用加锁,或者使用atomic.Value进行原子替换
reference
https://juejin.cn/post/6844903702373859335
内存管理
参考TCMalloc,Thread Cache Malloc,Go的内存管理借鉴了TCMalloc。
内存碎片:内存的不断申请和释放,内存会存在大量的碎片,降低内存使用率。为了解决内存碎片,可以将几个连续的未使用的内存块合并。
去大锁:每个线程的内存使用有一个大锁。
每个P会挂载一个mcache,goroutine程序申请小块内存时,会从mcache中分配,这样不用加锁。
所有工作线程还共用mcentral,mcache中不够用,就会去mcentral中获取。还有下一级的mhead,mheap中没有会到操作系统中要。
page:内存页,8k内存空间。Go和操作系统之间内存申请和释放,都是page单位。
span:内存块,一个或者连续多个page组成span。
- 原文作者:nepp
- 原文链接:https://nepp-an.github.io/post/golang%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。