我想在.Net中固定一些托管对象,将其数据复制到字节数组中。对于固定和复制,我使用下一个代码:
C c = new C();
byte[] b = new byte[Marshal.SizeOf(c)];
GCHandle gch = GCHandle.Alloc(c, GCHandleType.Pinned);
Marshal.Copy(gch.AddrOfPinnedObject(), b, 0, b.Length);
gch.Free();
当我将对象定义声明为:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct A
{
public int a;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct C
{
public A a0;
public A a1;
public A a2;
}
一切正常。当我将对象定义声明为:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct A
{
public int a;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
class C
{
public A a0;
public A a1;
public A a2;
}
所有工作都很好。但是当我将我的对象声明为 class :
时[StructLayout(LayoutKind.Sequential, Pack = 1)]
class A
{
public int a;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
class C
{
public A a0;
public A a1;
public A a2;
}
然后在 GCHandle.Alloc(...) 中抛出ArgumentException。对象包含非原始或非blittable数据。'
为什么当 A 被定义为struct时,一切正常。但是当班级没有工作的时候?可以使用A和C两种类型定义为类吗?
答案 0 :(得分:3)
您正试图打败垃圾收集器,您正在将引用复制到类对象中,而不是GC无法看到的内存块。这是无效的,这样的参考值在短至一纳秒后变成垃圾。每当GC运行时,您都不知道何时。 GC无法更新引用,它不知道它存在。
只有当这些引用指向的对象无法进行垃圾回收且无法移动时,才能正确执行此操作。换句话说,他们必须固定。你说服了编组,你可能会认为这是正确的:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
class C
{
public IntPtr a0;
public IntPtr a1;
public IntPtr a2;
}
您已经知道如何获取这些IntPtr值。使用CLR未检查的附加规定,只要其他代码可能正在使用内存blob,就会保留这些对象。