【问题标题】:C++ Memory Leak Passing a string to C# codeC++内存泄漏将字符串传递给C#代码
【发布时间】:2015-10-20 09:21:00
【问题描述】:

我们有一个 c# 应用程序,它使用回调方法从 c++ 项目接收数据:

/* c# code */
call[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private unsafe delegate void NewFrame(string serial, Int32* width, Int32* height, short* frame);

在我们的 C++ 项目(从相机接收数据)中,我们非常频繁地调用这个“NewFrame”回调方法,将相机帧传递给 c# 代码。

这个方法在c++中的定义是:

/* c++ code */
typedef void (__stdcall * NewFrame)(char* serialnumber, INT32* width,INT32* height, int16_t* frame);

要传递“序列”,在 c++ 代码中将 c++ 字符串对象转换为 char*:

/* c++ code */
char* stringToCsharpString(string s){
    char* cserial = new char[s.length() + 1];
    strcpy(cserial, s.c_str());
    return cserial;
}

但是,这会导致(堆)内存泄漏,因为 cserial 对象没有被释放。

这是在 c++ 中调用这个 NewFrame 方法的方式:

/* c++ code */
newFrame(stringToCsharpString(node.getSerialNumber()), &w, &h, data.frame);

我们可以做些什么来解决这个问题?我们精通c#,但一点也不精通c++。所以说c++代码的时候,请解释清楚:)

【问题讨论】:

  • 需要在c#包装对象的Dispose()方法中删除这个动态内存
  • 它还取决于 NewFrame 对字符串的处理方式。如果访问是只读的和同步的,并且指针没有存储在任何地方(即调用者等待完成并且NewFrame() 以某种方式复制和/或转换数据),您可以只使用s.c_str() 作为参数。
  • 无论如何,您都不应该跨模块边界传递诸如std::string 之类的类。 C# 对std::string 及其内部实现等一无所知。NewFrame 的参数应该只是指向 C# 创建的字符缓冲区(数组)的指针,不多也不少。
  • @PaulMcKenzie 只是为了避免误解——你的意思是参数应该是 C# 创建的缓冲区(而不是 C++,它是这里的调用者,数据的来源)?如果我们假设暂时使用在 C++ 端创建的缓冲区:s.c_string() 将符合“仅作为指向字符缓冲区的指针”的要求,因此您的(明智的)警告不会禁止它通过C++std::strings。我们同意吗?
  • @RonaldoMessi 我将如何删除这段记忆?我在 C# 中得到的只是一个字符串对象

标签: c# c++ memory-leaks


【解决方案1】:

为了在C#中将C++非托管内存转换为托管内存,可以使用gcnew

String^ ConvertUnmanagedString2ManagedString(char* cserial)
{
     return gcnew String(cserial)
}

在这里,我假设您的 cserial 内容编码当然是 UCS-2。我不知道 cserial 的内容是什么,但是如果它是用 UTF8 或 UCS-2 以外的其他编码编码的,你还需要应用文本编码转换,因为 C# 字符串编码是 UCS-2。

【讨论】:

    猜你喜欢
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-19
    相关资源
    最近更新 更多