当前位置: 首页 > news >正文

cgo内存泄漏排查

示例程序:

package main/*
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char* cMalloc() {char *mem = (char*)malloc(1024 * 1024 * 16);return mem;
}
void cMemset(char* mem) {memset(mem, '-', 1024 * 1024 * 16);
}
int arrLen = 1000;
int arrIndex;
char* globalMemAddr[1000];
void printAddr(char* mem) {if (arrIndex+1 >= arrLen) {arrIndex = 0;} else {arrIndex++;}globalMemAddr[arrIndex] = mem;printf("index: %d, addr: %p\n", arrIndex, globalMemAddr[arrIndex]);
}
*/
import "C"
import ("fmt""net/http"_ "net/http/pprof""os""runtime""sync""time""unsafe"
)var size int = 1024 * 1024 * 16
var memStat runtime.MemStatsfunc main() {go func() {_ = http.ListenAndServe("0.0.0.0:9091", nil)}()if len(os.Args) > 1 && os.Args[1] == "1" {var wg sync.WaitGroupfor {wg.Add(1)runtime.ReadMemStats(&memStat)fmt.Printf("total memory begin: %v mb\n", memStat.TotalAlloc/1024/1024)go doCMalloc(&wg)wg.Wait()runtime.ReadMemStats(&memStat)fmt.Printf("total memory   end: %v mb\n", memStat.TotalAlloc/1024/1024)time.Sleep(2000 * time.Millisecond)}} else {var wg sync.WaitGroupfor {wg.Add(1)go doGoMalloc(&wg)wg.Wait()time.Sleep(2000 * time.Millisecond)}}
}// 无泄漏
func doCMalloc(wg *sync.WaitGroup) {defer wg.Done()cptr := C.cMalloc()C.cMemset(cptr)C.printAddr(cptr)bs := C.GoBytes(unsafe.Pointer(cptr), C.int(size))fmt.Printf("1: %s .. %s\n", string(bs[0:8]), string(bs[size-8:size]))C.free(unsafe.Pointer(cptr))
}// 无泄漏
func doGoMalloc(wg *sync.WaitGroup) {defer wg.Done()bs := make([]byte, size, size)cptr := (*C.char)(unsafe.Pointer(&bs[0]))C.cMemset(cptr)C.printAddr(cptr)fmt.Printf("2: %s .. %s\n", string(bs[0:8]), string(bs[size-8:size]))
}

运行分支1:

将doCMalloc函数内的C.free注释掉。

go build memleak.go
./memleak 1

查看控制台输出:

查看top输出:

查看pprof输出:

#yum install graphvizgo tool pprof -http=192.168.36.5:9000 http://127.0.0.1:9091/debug/pprof/allocs

常规go工具链无法监测cgo内存:

top显示进程占用1.7g,inuse_space显示占用16mb,runtime.ReadMemStats显示分配过1442mb,alloc_space显示doCMalloc函数分配过944mb。

可以发现:不管是runtime.ReadMemStats还是pprof都不包含cgo内通过c语言分配的内存的占用情况,不能反映真实的进程占用内存情况。

内存泄漏检测之valgrind

centos8安装:

yum install valgrind --nogpgcheck

执行泄漏检测:

将doCMalloc函数内的C.free注释掉。

将代码中的arrLen调小便于出现泄漏,如调成10。

valgrind --tool=memcheck --leak-check=full --error-limit=no --trace-children=yes --show-leak-kinds=all --track-origins=yes --log-file=./vlog.txt ./memleak 1

检测结果:

给出了泄漏位置:at 0x4C38185: malloc (vg_replace_malloc.c:442)

内存泄漏检测之bcc/tools/memleak

centos8(kernel:4.18.0)安装:

(centos7不支持,需要自己升级内核到4.x版本)

bcc/INSTALL.md at master · iovisor/bcc · GitHub

yum install bcc-tools --nogpgcheck

执行泄漏检测:

将doCMalloc函数内的C.free注释掉。

将代码中的arrLen调小便于出现泄漏,如调成10。

/usr/share/bcc/tools/memleak -a -p `pidof memleak`

对于golang来说如果从程序一启动就执行监测,效果不理想,因为top10可能都是golang正常管理的内存,需要等到所有运行需要的golang管理的内存都预热到go的三级cache中,此时golang很少需要向系统申请内存了,再监测cgo的内存泄漏。

如从启动开始监测:

最好在golang稳定运行后再开始监测,如:

清晰的定位到泄漏位置:0x00007faa43885a71      sysmalloc+0x7d1 [libc-2.28.so]

还可以指定监测最小的内存泄漏单位(byte),如我们监测大于等于16MB的泄漏:

/usr/share/bcc/tools/memleak --min-size 16777216 -a -p `pidof memleak`

恢复doCMalloc函数内的C.free,再执行监测:

未发现泄漏。

内存泄漏检测之strace

strace只能通过肉眼观察分配和回收是否配对出现或者由于缓存机制不再频繁申请内存,本身不能给出泄漏报告。

执行泄漏检测:

将doCMalloc函数内的C.free注释掉。

将代码中的arrLen调小便于出现泄漏,如调成10。

strace -e 'trace=brk,mmap,munmap' -f -p `ps aux | grep memleak | grep -v 'grep' | awk '{print $2}'`

泄漏情况观察如图:

未泄漏情况观察:

恢复doCMalloc函数内的C.free。

从启动时开始监测:

strace -e 'trace=brk,mmap,munmap' -f ./memleak 1 &> slog &
tail -f slog

显示16mb+的空间分配或映射只在程序启动不久时出现了,之后再没有出现。

--end--


http://www.mrgr.cn/news/79182.html

相关文章:

  • 图解SSH原理
  • 视频自定义全屏功能——兼容安卓和ios
  • RTMP推流平台EasyDSS在无人机推流直播安防监控中的创新应用
  • 爬虫基础知识点
  • 【最新】北大数字普惠金融指数数据集-省市县(2011-2023年)
  • Maven 安装配置(详细教程)
  • 微信小程序版小米商城的搭建流程详解!
  • Springboot 2.x 升级到Springboot 2.7.x问题汇总
  • mysql集群NDB方式部署
  • 基于python爬虫的智慧人才数据分析系统
  • string类函数的手动实现
  • mysql中的skip_name_resolve详解
  • 速通SpringBoot+vue全栈开发教程
  • 贪心算法题
  • Python3:pytest+request+yaml+allure接口自动化测试
  • <工具 Claude Desktop> 配置 MCP server 连接本地 SQLite, 本机文件夹(目录) 网络驱动器 Windows 11 系统
  • 4. IO Stream
  • 工业—使用Flink处理Kafka中的数据_ChangeRecord2
  • PHP语法学习(第三天)
  • 深入浅出:Go语言中map的工作原理详解
  • Redis设计与实现读书笔记
  • 万字长文解读深度学习——dVAE(DALL·E的核心部件)
  • centos 手动安装libcurl4-openssl-dev库
  • (12)时间序列预测之MICN(CNN)
  • 基于ZooKeeper搭建Hadoop高可用集群
  • 深入浅出:Python 编程语言的学习之路