一、这篇文章我们来聊聊Golang内存管理和垃圾回收,主要注重基本底层原理讲解,进一步实战待后续文章
1、这篇我们来讨论一下Golang的内存管理
先上结构图
从图我们来讲Golang的基本内存结构,内存结构可以分为:协程缓存、中央缓存和页堆,还有底层的虚拟内存,虚拟内存我们不用太关心,可以看成操作系统那一层面的内容。
其实看到Golang的内存结构,其实和操作系统的内存管理的道理是相同的。
为什么需要在协程基本上设立一个缓存区域?
目的就是为了访问加速,让一部分内存单元直接属于某个协程。如果没有这种协程缓存,每个协程都从公共的中央缓存中,抢占内存单元,会发生很多资源抢占、并发安全问题,得不偿失。
那么中央缓存是干啥的,图我们可以看到中央缓存是有多个的,为了便于理解(如有错误,请评论区指正),笔者表述为每个中央缓存都会统一管理某个类别下的内存管理单元,一个类别或者说某个中央缓存下,可能包含了多个协程需要的内存单元。
对于每个中央缓存的内存单元,属于该类别的协程来申请内存单元时,申请是要加锁的,可以一个看到共性,对于公共区域,为了保证访问的一致性,对于资源的占用,都是要加锁的。
那么这里就会有一个问题,这些内存单元是如何进行管理的,总不可能看到一个内存单元,看一下他能不能用吧?这太傻了吧。
所以,在各级别缓存中,对于内存管理单元,分为空闲内存单元和已使用的内存单元区域,在每个类别区域下,根据内存单元大小进行分类,每个类别下构成一个以内存单元为节点的单链表。那么协程申请内存的时候,其实是需要根据你申请的对象大小,来决定你的内存单元是从协程缓存、中央缓存和页堆的哪个进行分配。后续我们再讲这个问题。
那页堆是干嘛的,如果你是学过Java,也可以直接理解成堆,不过既然是讲Golang,我们给出一个稍微规范一点的定义,他就是管理全局内存单元的,所有内存单元都来自于页堆。
前面我们已经说了,内存管理单元在各级内存空间中,是如何进行管理的,那么申请一个对象是如何申请的,笔者给一个口语化理解
Golang申请内存单元的行为,根据申请内存大小分为了微小大对象,针对大对象(32KB以上)的内存分配可能直接申请页堆的内存管理单元,微、小对象可以在协程缓存或中央缓存进行申请,如果上一级内存空间不足时,会向下一级内存空间申请内存管理单元,这里说的级别是协程缓存、中央缓存和页堆,级别从左到右依次递增。从中央缓存开始,申请内存单元时要加锁的。
哈哈,有说的不对的地方敬请指教,写文不易,给俺一个点赞和收藏吧哈哈。