非托管和托管内存区域
我正在尝试从 C 库执行非托管代码。其中一种方法将 avoid*
作为参数,但在幕后它被强制转换为类型的结构nc_vlen_t
nc_vlen_t 的 C 结构
/** This is the type of arrays of vlens. */
typedef struct {
size_t len; /**< Length of VL data (in base type units) */
void *p; /**< Pointer to VL data */
} nc_vlen_t;
执行该方法是正确的并且有效,我更关心托管和非托管内存区域的固定和安全处理。我想尽可能确定我不会导致内存泄漏或 SEGFAULT。我编写了一个结构,它将nc_vlen_t
在我执行 C 库方法调用时进行编组。
C# 结构
[StructLayout(LayoutKind.Sequential)]
public struct VlenStruct {
public Int32 len;
public IntPtr p; // Data
}
该结构由size_t
表示数组长度的 a 和void *
数据的 a 组成。在库内部,它具有允许将 (void*) 转换为适当的数字类型的属性,到目前为止,我已经取得了巨大的成功。
我想了解的是处理内存区域的最佳方式。在阅读了一些文章和其他 SO 问题之后,这是我对如何处理它的最佳猜测。我有一个类充当创建和管理结构及其内存的仲裁者。我依靠析构函数来释放将取消固定数组的句柄,以便 GC 可以完成它的工作。
C# Vlen 助手
public class Vlen {
private GCHandle handle;
private VlenStruct vlen_t;
public Vlen() {
isNull = true;
}
public Vlen(Array t) {
isNull = false;
handle = GCHandle.Alloc(t, GCHandleType.Pinned); // Pin the array
vlen_t.len = t.Length;
vlen_t.p = Marshal.UnsafeAddrOfPinnedArrayElement(t, 0); // Get the pointer for &t[0]
}
~Vlen() {
if(!isNull) {
handle.Free(); // Unpin the array
}
}
public VlenStruct ToStruct() {
VlenStruct retval = new VlenStruct();
retval.len = vlen_t.len;
retval.p = vlen_t.p;
return retval;
}
private bool isNull;
}
C 方法声明
//int cmethod(const int* typep, void *data)
// cmethod copies the array contents of the vlen struct to a file
// returns 0 after successful write
// returns -1 on fail
[DllImport("somelib.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true, CallingConvention=CallingConvention.Cdecl)]
public static extern Int32 cmethod(ref Int32 typep, ref VlenStruct data);
如果我使用此类来创建结构,在这种情况下,GC 可能会在调用 C 库之前清理数组:
C# 用例
{
double[] buffer vlenBuffer = new double[] { 0, 12, 4};
Vlen data = new Vlen(vlenBuffer); // The instance now pins buffer
VlenStruct s = data.ToStruct()
Int32 type = VLEN_TYPE;
cmethod(ref type, ref s);
}
是否data
可以清理实例并因此取消固定buffer
,这可能会在执行外部库方法时导致不可预测的行为?