网站建设 APP,西安最新消息,wordpress5.2多站点设置方法,wordpress文本目录golang使用mmap来优化gc#xff1a;
背景 需要处理的对象非常多时#xff0c;比如#xff1a;时序数据库victoriametrics源码中#xff0c;利用了mmap申请内存并自己维护#xff0c;从而避免过多gc影响性能#xff0c;因为频繁申请和释放堆对象会降低性能 参考victoriam…golang使用mmap来优化gc
背景 需要处理的对象非常多时比如时序数据库victoriametrics源码中利用了mmap申请内存并自己维护从而避免过多gc影响性能因为频繁申请和释放堆对象会降低性能 参考victoriametrics malloc_mmap.go
example
package mainimport (flagfmtruntimeruntime/debugtimegolang.org/x/sys/unix
)const size 3 * 1024 * 1024 * 1024 // 3GB
const hello hellofunc allocateMemory(useMmap bool) []byte {if useMmap {data, err : unix.Mmap(-1, 0, int(size), unix.PROT_READ|unix.PROT_WRITE, unix.MAP_ANON|unix.MAP_PRIVATE)if err ! nil {fmt.Println(Error creating memory mapping:, err)return nil}// 将 hello 写入满整个内存for i : 0; i size; i len(hello) {copy(data[i:min(ilen(hello), size)], []byte(hello))}return data}// 使用 make 分配内存并写入满整个内存data : make([]byte, size)for i : 0; i size; i len(hello) {copy(data[i:min(ilen(hello), size)], []byte(hello))}return data
}func min(a, b int) int {if a b {return a}return b
}// 打印 GC 统计信息和当前内存情况
func printGCStatsAndMemoryInfo(label string, data []byte) {var stats debug.GCStatsdebug.ReadGCStats(stats)var memStats runtime.MemStatsruntime.ReadMemStats(memStats)fmt.Printf(%s GC Stats: LastGC%v, NumGC%d, PauseTotal%v\n, label, stats.LastGC, stats.NumGC, stats.PauseTotal)fmt.Printf(%s Memory Stats: Alloc%v, TotalAlloc%v, Sys%v, NumGC%v\n, label, memStats.Alloc, memStats.TotalAlloc, memStats.Sys, memStats.NumGC)fmt.Printf(%s Current Memory: %v bytes\n, label, len(data))
}func main() {useMmap : flag.Bool(usemmap, false, Specify whether to use mmap for memory allocation (default: false))flag.Parse()if *useMmap {fmt.Println(Using mmap for memory allocation)} else {fmt.Println(Not using mmap for memory allocation)}// 定期打印 GC 执行情况和当前内存情况ticker : time.NewTicker(2 * time.Second)defer ticker.Stop()data : allocateMemory(*useMmap)defer func() {if *useMmap {unix.Munmap(data)}}()for {select {case -ticker.C:// 每隔2秒打印一次printGCStatsAndMemoryInfo(Current, data)}}
}使用go的堆内存看到当前的内存占用了3G且go的gc感知到这部分的所以gc需要扫的内存是很多的而这部分是常驻的话又不会被回收所以导致不必要的gc压力
[root ~]# ./gc-test
Not using mmap for memory allocation
Current GC Stats: LastGC2024-01-29 15:10:45.747195763 0800 CST, NumGC1, PauseTotal185.526µs
Current Memory Stats: Alloc3221337272, TotalAlloc3221338128, Sys3283418896, NumGC1
Current Current Memory: 3221225472 bytes
Current GC Stats: LastGC2024-01-29 15:10:45.747195763 0800 CST, NumGC1, PauseTotal185.526µs
Current Memory Stats: Alloc3221355080, TotalAlloc3221355936, Sys3283418896, NumGC1
Current Current Memory: 3221225472 bytes
...
...使用top看其实都占用了3GPID USER PR NI VIRT RES SHR S %CPU %MEM TIME COMMAND319166 root 20 0 4425716 3.1g 1320 S 0.0 19.9 0:05.94 gc-test使用mmap看到虽然当前的内存占用了3G但是go的gc感知不到这部分的所以gc需要扫的内存是很少的
[root ~]# ./gc-test -usemmap
Using mmap for memory allocation
Current GC Stats: LastGC1970-01-01 08:00:00 0800 CST, NumGC0, PauseTotal0s
Current Memory Stats: Alloc105856, TotalAlloc105856, Sys7183376, NumGC0
Current Current Memory: 3221225472 bytes
Current GC Stats: LastGC1970-01-01 08:00:00 0800 CST, NumGC0, PauseTotal0s
Current Memory Stats: Alloc122184, TotalAlloc122184, Sys7183376, NumGC0
Current Current Memory: 3221225472 bytes
...
...使用top看其实都占用了3GPID USER PR NI VIRT RES SHR S %CPU %MEM TIME COMMAND319179 root 20 0 4372212 3.0g 1320 S 0.0 19.6 0:05.23 gc-test结论虽然在go堆内分配内存和使用mmap分配内存在进程外的视角是一样的但是在go runtime视角上是看不到mmap这部分的所以不会去进行gc扫描的可以减轻压力 所以对于常驻大内存使用mmap性能更高但是要自己维护好分配和释放否则会导致内存泄漏