CGO: how to free memory allocated in C using malloc from go to avoid memory leak

huangapple go评论91阅读模式
英文:

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 &lt;stdio.h&gt;
//#include &lt;stdlib.h&gt;
//#include &lt;string.h&gt;
//char* echo(char* s);
import &quot;C&quot;
import &quot;unsafe&quot;

func main() {
	cs := C.CString(&quot;Hello from stdio\n&quot;)
	defer C.free(unsafe.Pointer(cs))
	var echoOut *C.char = C.echo(cs)
	//defer C.free(unsafe.Pointer(echoOut)); -&gt; using this will crash the code
	fmt.Println(C.GoString(echoOut));
}

algo.cpp

<!-- language: lang-c++ -->

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;iostream&gt;
#include &lt;math.h&gt;

using namespace std;

extern &quot;C&quot; {
    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 &lt;stdio.h&gt;
//#include &lt;stdlib.h&gt;
//#include &lt;string.h&gt;
//char* echo(char* s);
import &quot;C&quot;
import (
	&quot;fmt&quot;
	&quot;unsafe&quot;
)

func main() {
	cs := C.CString(&quot;Hello from stdio\n&quot;)
	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 &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;iostream&gt;
#include &lt;math.h&gt;

using namespace std;

extern &quot;C&quot; {
    char* echo(char* o) {
        char* out = (char*)malloc(strlen(o)+1);
        strcpy(out, o);
        return out;
    }
}

Output:

$ cd algo
$ go build &amp;&amp; ./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 &lt;stdio.h&gt;
//#include &lt;stdlib.h&gt;
//#include &lt;string.h&gt;
//char* echo(char* s);
import &quot;C&quot;
import &quot;unsafe&quot;

func main() {
	for i := 0; i &lt; 1000000000; i++ {
		allocateAndDeallocate()
	}
}

func allocateAndDeallocate() {
	cs := C.CString(&quot;Hello from stdio\n&quot;)
	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 &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;iostream&gt;
#include &lt;math.h&gt;

using namespace std;

extern &quot;C&quot; {

	char* echo(char* o) {
        int len = sizeof(o) / sizeof(char);
        char* out = (char*)malloc(len * sizeof(char));
        strcpy(out, o);
        return out;
    }

}    

huangapple
  • 本文由 发表于 2016年2月19日 22:18:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/35507467.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定