【发布时间】:2017-11-09 17:07:54
【问题描述】:
这是我的代码:
helloworld.go:
package main
/*
#include <stdlib.h>
*/
import "C"
import "unsafe"
//export HelloWorld
func HelloWorld() *C.char {
cs := C.CString("Hello World!")
C.free(unsafe.Pointer(cs))
return cs
}
func main() {}
node-helloworld.cc:
#include "helloworld.h"
#include <node.h>
#include <string>
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
void Method(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(String::NewFromUtf8(isolate, HelloWorld()));
}
void init(Local<Object> exports) {
NODE_SET_METHOD(exports, "hello", Method);
}
NODE_MODULE(helloworld, init)
}
当我执行我得到的代码时:
�Oc
或
��#
或
����
等
实际上是随机的。我似乎每次都得到不同的东西。
可能是我从 HelloWorld() 方法传递 char 数组。
我错过了什么?
更新
当我删除时:
C.free(unsafe.Pointer(cs))
我得到了好的字符串。而不是随机字符。
但我需要C.free 来释放内存。这里推荐:https://blog.golang.org/c-go-cgo
对 C.CString 的调用返回一个指向字符开头的指针 数组,所以在函数退出之前我们将它转换为一个 unsafe.Pointer 并使用 C.free 释放内存分配。
我不确定该怎么做。
【问题讨论】:
-
我不熟悉 go,但是返回一个释放的
cs对我来说看起来很可疑 -
cs只是一个变量。实际上,我只记得如果我删除:C.free(unsafe.Pointer(cs))我实际上得到了整个字符串。现在的问题是我没有像这里推荐的那样清除内存:blog.golang.org/c-go-cgo -
请不要在未考虑所提供示例中发生的情况的情况下应用那里所写的内容。在那里,他们获取一个 Go 字符串,将其转换为 C 字符串(内部调用
C.malloc()),然后将该 C 字符串传递给C.fputs()函数,该函数*读取该内存并将其中的字符输出到标准输出流.在该调用返回后,该内存可被视为“完成”,因此需要释放。 -
换句话说,没有发生所有权转移:我们已经分配了内存,然后调用了一个仅从中读取的函数,所以当它退出时,我们仍然拥有该内存区域,因为它不是不再需要,我们必须释放它。在这方面,您自己的代码完全不同:您在 Go 代码中分配内存,并想将此内存块转移到其他代码,以便它进一步处理它它认为合适。 这是所有权的明确转移,因此您的 Node 代码必须负责释放该内存块。
-
让我回顾一下:不要盲目地应用你在某处读到的任何东西:试着思考为什么代码会做任何事情;不要只是试图挤压像“好的,所有对
C.CString()和C.free()的调用无论出于何种原因都必须成对出现”之类的模式。当没有垃圾收集(这是 C)时,在任何给定时间,任何分配的内存区域都由正在运行的代码的某些部分“拥有”。在某些语言(比如 Rust)中,这是明确的;在 C 中,它是隐式的,因此请始终考虑哪些代码必须负责每个分配的内存块。