c# - 如何释放 C# 中从 Rust 返回的字符串的内存?

标签 c# memory-management memory-leaks rust ffi

我从 Rust

中公开了这两个函数
extern crate libc;

use std::mem;
use std::ffi::{CString, CStr};

use libc::c_char;

pub static FFI_LIB_VERSION: &'static str = env!("CARGO_PKG_VERSION"); // '

#[no_mangle]
pub extern "C" fn rustffi_get_version() -> *const c_char {
    let s = CString::new(FFI_LIB_VERSION).unwrap();
    let p = s.as_ptr();
    mem::forget(s);

    p as *const _
}

#[no_mangle]
pub extern "C" fn rustffi_get_version_free(s: *mut c_char) {
    unsafe {
        if s.is_null() {
            return;
        }

        let c_str: &CStr = CStr::from_ptr(s);
        let bytes_len: usize = c_str.to_bytes_with_nul().len();
        let temp_vec: Vec<c_char> = Vec::from_raw_parts(s, bytes_len, bytes_len);
    }
}

fn main() {}

它们由 C# 导入,如下所示

namespace rustFfiLibrary
{
    public class RustFfiApi
    {
        [DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version")]
        public static extern string rustffi_get_version();

        [DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version_free")]
        public static extern void rustffi_get_version_free(string s);

    }
}

rustffi_get_version 返回的字符串内存不再由 Rust 管理,因为 mem::forget 已被调用。在 C# 中,我想调用获取版本函数,获取字符串,然后将其传递回 Rust 以进行内存释放,如下所示。

public class RustService
{
    public static string GetVersion()
    {
        string temp = RustFfiApi.rustffi_get_version();
        string ver = (string)temp.Clone();

        RustFfiApi.rustffi_get_version_free(temp);

        return ver ;
    }
}

但是C#程序在运行rustffi_get_version_free(temp)时崩溃了。如何在 C# 中释放被遗忘的字符串内存?应该将什么传递回 Rust 以进行释放?

我没有将 string 定义为 C# extern 中的参数,而是将其更改为 pointer

[DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version")]
public static extern System.IntPtr rustffi_get_version();

[DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version_free")]
public static extern void rustffi_get_version_free(System.IntPtr s);
public static string GetVersion()
{
    System.IntPtr tempPointer = RustFfiApi.rustffi_get_version();
    string tempString = Marshal.PtrToStringAnsi(tempPointer);

    string ver = (string)tempString.Clone();

    RustFfiApi.rustffi_get_version_free(tempPointer);

    return ver ;
}

rustffi_get_version 中的IntPtr 可以成功转换为 C# 托管字符串类型。 tempStringver 都不错。

rustffi_get_version_free(tempPointer) 运行时,它会抛出一个异常,提示 stack unbalanced:

A call to PInvoke function 'rustFfiLibrary!rustFfiLibrary.RustFfiApi::rustffi_get_version_free' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

sizeof(IntPtr)sizeof(char *) 在我的系统上都是 4。另外,IntPtr 用于返回值;为什么它不能用作输入参数?

最佳答案

extern "C"fn 在 Rust 中表示该函数使用 C 调用约定。 C# 期望 P/Invoke 函数默认使用 stdcall 调用约定。

您可以告诉 C# 使用 C 调用约定:

[DllImport("rustffilib.dll", CallingConvention = CallingConvention.Cdecl)]

或者,您可以在 Rust 端使用 extern "stdcall"fn

关于c# - 如何释放 C# 中从 Rust 返回的字符串的内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34737626/

相关文章:

c# - 尽管 CanUserSortColumns ="true",但使用 ItemsSource 填充的 DataGrid 无法排序

c# - 从 Web 服务调用方法时 SessionId 发生变化

iphone - 有没有什么可以使 iPhone/iPod Touch 应用程序编程的内存管理更容易?

CleanMem 工具 - 自动释放 Windows 上分配的内存?

c++ - Visual Studio C++ 项目中的奇怪内存泄漏

c# - 无法向线程池添加任何内容

c# - 在 System.Data.Sqlite (.net) 中启用共享缓存模式

c++ - 在结构中访问 std::list 会引发段错误

java - GWT 中必要的解除绑定(bind)演示者

Javascript 计时器内存泄漏