2016-02-19 455 views
1

我想使用CGO從golang調用複雜算法的優化C++ CPU綁定實現。基本上,它會將一個字符串傳遞給C++函數並返回一個字符串。代碼的簡化版本可以看出在下面:CGO:如何釋放內存中使用malloc分配的內存,以避免內存泄漏

//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; 
    } 
}  

在這種鏈路,PPL提到,C++代碼應該調用「自由」本身以釋放分配的內存: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?應該怎樣處理這個問題?我有一個網絡服務器會調用每個請求的C++代碼,並希望確保它不會引入任何內存泄漏。

謝謝。

+0

你說調用'C.free'崩潰的代碼。什麼是錯誤?什麼是堆棧跟蹤看起來像?在Go中調用'C.free'完全就像在C中調用它。你必須知道是誰負責釋放內存,什麼時候可以安全。 – JimB

+0

嗨,謝謝。我的代碼崩潰了,因爲我錯誤地在C++中分配了內存。但我只是注意到,即使修復了分配的內存錯誤,我的代碼仍然遭受內存泄漏問題。看來,我將不得不在C++代碼中釋放內存或傳遞指向C++指針的指針(避免使用malloc)將字符串從C++代碼傳遞迴gocode的正確方法是什麼? – auxdx

+0

似乎內存泄漏是因爲我的代碼的其他部分。謝謝。 – auxdx

回答

1

修復您的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 

$ 
+0

謝謝。有用。但我仍然想知道是否應該使用defer C.free(unsafe.Pointer(echoOut))釋放內存,還是必須在C++代碼中的某個位置? – auxdx

+0

順便說一句,我只是意識到我的代碼泄漏內存。似乎我將不得不釋放C++ malloc'ed內存或傳遞指向C++代碼的指針。有什麼建議麼? – auxdx

0

我用下面去版本go version go1.8 linux/amd64,我有運行沒有問題的取消註釋延期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; 
    } 

}