April 26, 2021
docker如何利用cgroup对容器资源进行限制
"在容器里有两个非常重要的概念,一个是 namespace 用来实现对容器里所有进程进行隔离;另一个就是 cgroup,用来对容器进程内使用资源进行限制。那 cgroup 又是如何实现对资源进行限制的呢,今天我们来了解一下它的实现原理。\n什么是cgroup cgroup 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离 进程组 所使用的物理资源(如 cpu、memory、磁盘IO等等) 的机制,被 LXC、docker 等很多项目用于实现进程资源控制。cgroup 是将任意进程进行分组化管理的 Linux 内核功能。 cgroup 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。 一定要切记,这里的限制单元为 进程组,而不是进程。\n子系统 上面提到的具体的资源管理功能统称为 cgroup 子系统,所有子系统列表可以通过 cat /proc/cgroups 命令查看,主要有以下几大子系统:\n# cat /proc/cgroups #subsys_name\thierarchy …"
April 12, 2021
Golang 内存组件之mspan、mcache、mcentral 和 mheap 数据结构
"Golang中的内存组件关系如下图所示golang 内存分配组件\n在学习golang 内存时,经常会涉及几个重要的数据结构,如果不熟悉它们的情况下,理解起来就显得格外的吃力,所以本篇主要对相关的几个内存组件做下数据结构的介绍。\n在 Golang 中,mcache、mspan、mcentral 和 mheap 是内存管理的四大组件,mcache 管理线程在本地缓存的 mspan,而 mcentral 管理着全局的 mspan 为所有 mcache 提供所有线程。\n根据分配对象的大小,内部会使用不同的内存分配机制,详细参考函数 mallocgo() ,所于内存分配与回收,参考文件介绍 malloc.go\n\u0026lt;16KB 会使用微小对象内存分配器从 P 中的 mcache 分配,主要使用 mcache.tinyXXX 这类的字段 16-32KB 从 P 中的 mcache 中分配 \u0026gt;32KB 直接从 mheap 中分配 对于golang中的内存申请流程,大家应该都非常熟悉了,这里不再进行详细描述。Golang 内存组件关系\nmcache 在GPM关系中,会在每个 P …"
April 9, 2021
GC 对根对象扫描实现的源码分析
"工作池gcWork 工作缓存池(work pool)实现了生产者和消费者模型,用于指向灰色对象。一个灰色对象在工作队列中被扫描标记,一个黑色对象表示已被标记不在队列中。\n写屏障、根发现、栈扫描和对象扫描都会生成一个指向灰色对象的指针。扫描消费时会指向这个灰色对象,从而将先其变为黑色,再扫描它们,此时可能会产生一个新的指针指向灰色对象。这个就是三色标记法的基本知识点,应该很好理解。\ngcWork 是为垃圾回收器提供的一个生产和消费工作接口。\n它可以用在stack上,如\n(preemption must be disabled) gcw := \u0026amp;getg().m.p.ptr().gcw .. call gcw.put() to produce and gcw.tryGet() to consume .. 在标记阶段使用gcWork可以防止垃圾收集器转换到标记终止,这一点很重要,因为gcWork可能在本地持有GC工作缓冲区。可以通过禁用抢占(systemstack 或 acquirem)来实现。\n数据结构\ntype gcWork struct { wbuf1, wbuf2 …"
April 7, 2021
Runtime: Golang GC源码分析
"在阅读此文前,需要先了解一下三色标记法以及混合写屏障这些概念。\n源文件 [src/runtime/mgc.go](https://github.com/golang/go/blob/go1.16/src/runtime/mgc.go) 版本 1.16.2。\n基本知识 在介绍GC之前,我们需要认识有些与GC相关的基本信息,如GC的状态、模式、统计信息等。\n三种状态 共有三种状态\nconst ( _GCoff = iota // GC not running; sweeping in background, write barrier disabled _GCmark // GC marking roots and workbufs: allocate black, write barrier ENABLED _GCmarktermination // GC mark termination: allocate black, P\u0026#39;s help GC, write barrier ENABLED ) _GCoff GC未运行 _GCmark 标记中, …"
April 6, 2021
Golang中的切片与GC
"今天再看 timer 源码的时候,在函数 [clearDeletedTimers()](https://github.com/golang/go/blob/go1.16.2/src/runtime/time.go#L904-L992) 里看到一段对切片的处理代码,实现目的就是对一个切片内容进行缩容。\n// src/runtime/time.go // The caller must have locked the timers for pp. func clearDeletedTimers(pp *p) { timers := pp.timers ...... // 对无用的切片元素赋值 nil for i := to; i \u0026lt; len(timers); i++ { timers[i] = nil } atomic.Xadd(\u0026amp;pp.deletedTimers, -cdel) atomic.Xadd(\u0026amp;pp.numTimers, -cdel) atomic.Xadd(\u0026amp;pp.adjustTimers, -cearlier) timers = …"
March 29, 2021
Runtime: Golang 定时器实现原理及源码解析
"定时器作为开发经常使用的一种数据类型,是每个开发者需要掌握的,对于一个高级开发很有必要了解它的实现原理,今天我们runtime源码来学习一下它的底层实现。\n定时器分两种,分别为 Timer 和 Ticker,两者差不多,这里重点以Timer为例。\n源文件位于 [src/time/sleep.go](https://github.com/golang/go/blob/go1.16.2/src/time/sleep.go) 和 [src/time/tick.go](https://github.com/golang/go/blob/go1.16.2/src/time/tick.go) 。 go version 1.16.2\n数据结构 Timer 数据结构\n// src/runtime/sleep.go // The Timer type represents a single event. // When the Timer expires, the current time will be sent on C, // unless the Timer was created by …"
March 28, 2021
Golang中的CAS原子操作 和 锁
"在高并发编程中,经常会出现对同一个资源并发访问修改的情况,为了保证最终结果的正确性,一般会使用 锁 和 CAS原子操作 来实现。\n如要对一个变量进行计数统计,两种实现方式分别为\npackage main import ( \u0026#34;fmt\u0026#34; \u0026#34;sync\u0026#34; ) // 锁实现方式 func main() { var count int64 var wg sync.WaitGroup var mu sync.Mutex for i := 0; i \u0026lt; 10000; i++ { wg.Add(1) go func(wg *sync.WaitGroup) { defer wg.Done() mu.Lock() count = count + 1 mu.Unlock() }(\u0026amp;wg) } wg.Wait() // count = 10000 fmt.Println(\u0026#34;count = \u0026#34;, count) } 与\npackage main import ( \u0026#34;fmt\u0026#34; \u0026#34;sync\u0026#34; …"
March 23, 2021
Golang并发同步原语之-信号量Semaphore
"信号量是并发编程中比较常见的一种同步机制,它会保持资源计数器一直在0-N(N表示权重值大小,在用户初始化时指定)之间。当用户获取的时候会减少一点,使用完毕后再恢复过来。当遇到请求时资源不够的情况下,将会进入休眠状态以等待其它进程释放资源。\n在 Golang 官方扩展库中为我们提供了一个基于权重的信号量 [semaphore](https://github.com/golang/sync/blob/master/semaphore/semaphore.go) 并发原语。\n你可以将下面的参数 n 理解为资源权重总和,表示每次获取时的权重;也可以理解为资源数量,表示每次获取时必须一次性获取的资源数量。为了理解方便,这里直接将其理解为资源数量。\n数据结构 [semaphoreWeighted](https://github.com/golang/sync/blob/master/semaphore/semaphore.go#L19-L33) 结构体\ntype waiter struct { n int64 ready chan\u0026lt;- struct{} // Closed when …"
March 22, 2021
学习Golang GC 必知的几个知识点
"对于gc的介绍主要位于 [src/runtime/mgc.go](https://github.com/golang/go/blob/go1.16.2/src/runtime/mgc.go),以下内容是对注释的翻译。\nGC 四个阶段 通过源文件注释得知GC共分四个阶段:\nGC 清理终止 (GC performs sweep termination) a. Stop the world, 每个P 进入GC safepoint(安全点),从此刻开始,万物静止。 b. 清理未被清理的span,如果GC被强制执行时才会出现这些未清理的span GC 标记阶段(GC performs the mark phase) a. 将gc标记从 _GCoff 修改为 _GCmark,开启写屏障(write barries)和 协助助手(mutator assists),将根对象放入队列。 在STW期间,在所有P都启用写屏障之前不会有什么对象被扫描。 b. Start the world(恢复STW)。标记工作线程和协助助手并发的执行。对于任何指针的写操作和指针值,都会被写屏障覆盖,使新分配的对象标记为黑 …"
March 20, 2021
Runtime: Golang 之 sync.Pool 源码分析
"Pool 指一组可以单独保存和恢复的 临时对象。Pool 中的对象随时都有可能在没有收到任何通知的情况下被GC自动销毁移除。\n多个goroutine同时操作Pool是并发安全的。\n源文件为 [src/sync/pool.go](https://github.com/golang/go/blob/master/src/sync/pool.go) go version: 1.16.2\n为什么使用Pool 在开发高性能应用时,经常会有一些完全相同的对象需要频繁的创建和销毁,每次创建都需要在堆中分配对象,等使用完毕后,这些对象需要等待GC回收。我们知道在Golang中使用三色标记法进行垃圾回收的,在回收期间会有一个短暂STW(stop the world)的时间段,这样就会导致程序性能下降。\n那么能否实现类似数据库连接池这种效果,用来避免对象的频繁创建和销毁,达到尽可能的资源复用呢?为了实现这种需求,标准库中有了sync.Pool 这个数据结构。看名字很知道它是一个池。但是它和我们想象中的数据库连接池还是有些差别的。对于数据库连接池这种资源只要不手动释放就可以一直利用, …"