GO和CGO内存泄露排查

1,252 阅读2分钟

GO语言的内存泄露

排查Go语言内存泄露,毫无疑问的用pprof就好了,具体用法这篇文章中就不展开表述。

Cgo的内存泄露

怎么排查Cgo,网上相关的文章很少,可以使用pmap+gdb的方式来排查pmap+gdb排查内存泄露.但是这个方法太复杂了,对错误原因的提示不是特别友好。

如果使用fsanitize内存消毒来进行检测,就能很快的定位到哪个so或者哪个文件发生内存泄露,能定位到哪行代码发生了内存泄露,但是在cgo中,只能定位到某个文件某段内存是否发生内存泄露,而不能定位到具体的代码行,但是也减少了我们排查问题的时间。

排查内存泄露过程中有遇到一些坑,leak检测没有生效,原因是__lsan_do_leak_check没有在golang启动时注册,需要手动注册,参考 sanitizer-leak is not detected when golang using cgo to call c libary, 需要在代码中加上

void __lsan_do_leak_check(void);

的头文件引用

package main

// #include <stdio.h>
// #include <stdlib.h>
//
// void __lsan_do_leak_check(void);
//
// void leak_a_bit(void)
// {
//     char* p = malloc(2000);
//     printf("%p\n", p);
// }
import "C"

func main() {
        C.leak_a_bit()

        C.__lsan_do_leak_check()
}

然后编译中加上内存地址检测(可以和内存泄露共用)

CC="clang" CGO_CFLAGS="-fsanitize=address" CGO_LDFLAGS="-fsanitize=address" go run sanitizer.go


=================================================================
==30208==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 40 byte(s) in 1 object(s) allocated from:
    #0 0x49ac9b (/tmp/go-build1793173723/b001/exe/sanitizer+0x49ac9b)
    #1 0x5383fb (/tmp/go-build1793173723/b001/exe/sanitizer+0x5383fb)
    #2 0x538890 (/tmp/go-build1793173723/b001/exe/sanitizer+0x538890)
    #3 0x514f63 (/tmp/go-build1793173723/b001/exe/sanitizer+0x514f63)

SUMMARY: AddressSanitizer: 40 byte(s) leaked in 1 allocation(s).
exit status 23

centos中安装clang编译器

 yum -y install epel-release
 yum -y install clang