golang将指针传给cgo后还能被回收吗?

问题:

如果把golang分配的变量,其指针通过cgo传给c,并被c存储,那这个变量还能被gc回收吗?

实验代码:

test_memory_leak.go

Go 复制代码
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"
	"sync"
	"time"
	"unsafe"
)

var size int = 1024 * 1024 * 16

func main() {
	go func() {
		_ = http.ListenAndServe("0.0.0.0:9091", nil)
	}()
	if len(os.Args) > 1 && os.Args[1] == "1" {
		var wg sync.WaitGroup
		for {
			wg.Add(1)
			go doCMalloc(&wg)
			wg.Wait()
			time.Sleep(500 * time.Millisecond)
		}
	} else {
		var wg sync.WaitGroup
		for {
			wg.Add(1)
			go doGoMalloc(&wg)
			wg.Wait()
			time.Sleep(500 * 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]))
}

运行代码分支2:

GODEBUG=gctrace=1 ./test_memory_leak 2

终端显示:

top显示:

pprof数据:

go tool pprof -http=10.10.10.244:9000 http://127.0.0.1:9091/debug/pprof/allocs

alloc_objects:

inuse_space:

观察到的数据:

1、变量地址始终在0xc000180000和0xc001200000之间交换,说明内存被回收重复利用。

2、每次gc结束后内存始终控制在16MB。

3、进程使用的内存始终在40多MB,并没有太大变化。

4、inuse_space保持16MB不变,而alloc_objects在不断增长。

结论:

golang分配的变量,其指针被cgo引用,不影响golang对其进行垃圾回收。

--end--

相关推荐
浪子明X3 小时前
十六位账本怎样发现传输差错:Internet Checksum 生活类比
开发语言
xiangyun615 小时前
【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清
c语言·开发语言·数据结构·c++·算法
xiangyun615 小时前
【408数据结构 06】双链表、循环链表、静态链表
c语言·开发语言·数据结构·c++·算法
白远山7 小时前
家政服务家政社区派单实战:调度系统架构设计与实现指南
java·开发语言·小程序·架构·需求分析
DevRay8 小时前
Java 21虚拟线程深度实战:告别线程池焦虑,百万并发吞吐量直接翻倍(原理+代码+避坑)
java·开发语言
free-elcmacom8 小时前
C++学习<1>程序分区
开发语言·c++
醉颜凉8 小时前
Java 必看:如何彻底避免 HashMap 多线程死循环问题?
java·开发语言
默 语8 小时前
Java新手入门:从零开始安装JDK并配置环境变量
java·开发语言·python·mysql·group by·1024程序员节·数据去重
Brilliantwxx8 小时前
【STM32】 I2C_EEPROM_test 工程(实战篇)
开发语言·stm32·单片机·嵌入式硬件·ecmascript
清水白石0088 小时前
Python 异步编程深度解析:Cancellation 到底是异常还是控制信号?从 asyncio 取消机制到企业级事务设计最佳实践
开发语言·python