英文:
CGO: how to free memory allocated in C using malloc from go to avoid memory leak
问题
我正在尝试使用CGO从golang调用一个经过优化的C++ CPU密集型算法实现。基本上,它会将一个字符串传递给C++函数,并获得一个字符串作为返回值。下面是代码的简化版本:
algo.go
package main
//#cgo LDFLAGS:
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//char* echo(char* s);
import "C"
import "unsafe"
func main() {
cs := C.CString("Hello from stdio\n")
defer C.free(unsafe.Pointer(cs))
var echoOut *C.char = C.echo(cs)
//defer C.free(unsafe.Pointer(echoOut)); -> using this will crash the code
fmt.Println(C.GoString(echoOut))
}
algo.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
using namespace std;
extern "C" {
char* echo(char* o) {
int len = sizeof(o) / sizeof(char);
char* out = (char*)malloc(len * sizeof(char));
strcpy(out, o);
return out;
}
}
在这个链接中,有人提到C++代码应该自己调用"free"来释放分配的内存:http://grokbase.com/t/gg/golang-nuts/149hxezftf/go-nuts-cgo-is-it-safe-to-malloc-and-free-in-seperate-c-functions。但是这样做非常棘手,因为我的C++函数返回一个已分配的指针,以便golang可以获得结果。我不能在C++代码中调用free吗?应该如何正确处理这个问题?我有一个Web服务器,每个请求都会调用C++代码,并希望确保它不会引入任何内存泄漏。
谢谢。
英文:
I am trying to use CGO to call an optimized C++ CPU-bound implementation of a complex algorithms from golang. Basically, it will pass a string into c++ function and get a string back. A simplified version of the code can be seen in the below:
algo.go
<!-- language: lang-go -->
package main
//#cgo LDFLAGS:
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//char* echo(char* s);
import "C"
import "unsafe"
func main() {
cs := C.CString("Hello from stdio\n")
defer C.free(unsafe.Pointer(cs))
var echoOut *C.char = C.echo(cs)
//defer C.free(unsafe.Pointer(echoOut)); -> using this will crash the code
fmt.Println(C.GoString(echoOut));
}
algo.cpp
<!-- language: lang-c++ -->
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
using namespace std;
extern "C" {
char* echo(char* o) {
int len = sizeof(o) / sizeof(char);
char* out = (char*)malloc(len * sizeof(char));
strcpy(out, o);
return out;
}
}
In this link, ppl mentions that C++ code should call "free" by itself to free the allocated memory: http://grokbase.com/t/gg/golang-nuts/149hxezftf/go-nuts-cgo-is-it-safe-to-malloc-and-free-in-seperate-c-functions. But then it's very tricky because my c++ function return an allocated pointer so that golang can get the result. I cannot call free in the c++ code? What should be the correct way to handle this? I have a webserver will call the c++ code per each request and want to make sure it doesn't introduce any memory leak.
Thanks.
答案1
得分: 2
修复你的echo
函数中的内存分配错误。例如,
algo.go
:
//algo.go
package main
//#cgo LDFLAGS:
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//char* echo(char* s);
import "C"
import (
"fmt"
"unsafe"
)
func main() {
cs := C.CString("Hello from stdio\n")
defer C.free(unsafe.Pointer(cs))
var echoOut *C.char = C.echo(cs)
defer C.free(unsafe.Pointer(echoOut))
fmt.Println(C.GoString(echoOut))
}
algo.cpp
:
//algo.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
using namespace std;
extern "C" {
char* echo(char* o) {
char* out = (char*)malloc(strlen(o)+1);
strcpy(out, o);
return out;
}
}
输出:
$ cd algo
$ go build && ./algo
Hello from stdio
$
英文:
Fix the memory allocation bug in your echo
function. For example,
algo.go
:
<!-- language: lang-go -->
//algo.go
package main
//#cgo LDFLAGS:
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//char* echo(char* s);
import "C"
import (
"fmt"
"unsafe"
)
func main() {
cs := C.CString("Hello from stdio\n")
defer C.free(unsafe.Pointer(cs))
var echoOut *C.char = C.echo(cs)
defer C.free(unsafe.Pointer(echoOut))
fmt.Println(C.GoString(echoOut))
}
algo.cpp
:
<!-- language: lang-c++ -->
//algo.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
using namespace std;
extern "C" {
char* echo(char* o) {
char* out = (char*)malloc(strlen(o)+1);
strcpy(out, o);
return out;
}
}
Output:
$ cd algo
$ go build && ./algo
Hello from stdio
$
答案2
得分: 1
我正在使用以下go版本 go version go1.8 linux/amd64
,在取消注释你的deferred C.free后,运行你的代码没有任何问题。
我添加了一个循环,以便通过htop跟踪内存泄漏。如果不取消注释,它确实会泄漏,但取消注释后问题就解决了。
以下是代码。
//algo.go
package main
//#cgo LDFLAGS:
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//char* echo(char* s);
import "C"
import "unsafe"
func main() {
for i := 0; i < 1000000000; i++ {
allocateAndDeallocate()
}
}
func allocateAndDeallocate() {
cs := C.CString("Hello from stdio\n")
defer C.free(unsafe.Pointer(cs))
var echoOut *C.char = C.echo(cs)
defer C.free(unsafe.Pointer(echoOut)) // no crash here
}
//algo.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
using namespace std;
extern "C" {
char* echo(char* o) {
int len = sizeof(o) / sizeof(char);
char* out = (char*)malloc(len * sizeof(char));
strcpy(out, o);
return out;
}
}
希望对你有帮助!
英文:
I'm using the following go version go version go1.8 linux/amd64
and I have no problems running your code after uncommenting your deferred C.free.
I added a loop to allow me to track memory leaks via htop. Without the deferred free it does leak, but uncommenting it fixes the problem.
The code is below.
<!-- language: lang-go -->
//algo.go
package main
//#cgo LDFLAGS:
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//char* echo(char* s);
import "C"
import "unsafe"
func main() {
for i := 0; i < 1000000000; i++ {
allocateAndDeallocate()
}
}
func allocateAndDeallocate() {
cs := C.CString("Hello from stdio\n")
defer C.free(unsafe.Pointer(cs))
var echoOut *C.char = C.echo(cs)
defer C.free(unsafe.Pointer(echoOut)) // no crash here
}
<!-- language: lang-c++ -->
//algo.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
using namespace std;
extern "C" {
char* echo(char* o) {
int len = sizeof(o) / sizeof(char);
char* out = (char*)malloc(len * sizeof(char));
strcpy(out, o);
return out;
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论