持久性记忆混乱
Persistent memory confusion
我正在尝试了解 C# 中的持久内存,但不知道为什么这段代码没有保留其中一个函数中所做的更改。
using System;
using System.Runtime.InteropServices;
public class Test2
{
public struct value
{
public int sz;
}
public static void Main(string[] args)
{
one foo1 = new one(one_full);
two foo2 = new two(two_full);
make_calls(foo1, foo2);
}
public delegate void one(IntPtr ctx);
public static void one_full(IntPtr ctx)
{
/* set sz and see if persists */
GCHandle gch = GCHandle.FromIntPtr(ctx);
value val = (value)gch.Target;
val.sz = 6;
Console.WriteLine("Changed sz to be 6");
}
public delegate void two(IntPtr ctx);
public static void two_full(IntPtr ctx)
{
GCHandle gch = GCHandle.FromIntPtr(ctx);
value val = (value)gch.Target;
Console.Write("sz is = ");
Console.WriteLine(val.sz);
}
public static void make_calls(one f_one, two f_two)
{
value test = new value();
test.sz = 0;
IntPtr ptr = GCHandle.ToIntPtr(GCHandle.Alloc(test));
f_one(ptr);
f_two(ptr);
}
}
我知道最后缺少 free 但这只会导致混乱的内存管理....我正在寻找是否有人可以帮助我并解释为什么 sz 不保持为值 6当调用第二个函数时...
运行时的输出为:
Changed sz to be 6
sz is = 0
都是因为value
是一个struct
。
GCHandle.Alloc
需要一个object
参数,所以如果你传递一个struct
,它必须被装箱。
以后使用
value val = (value)gch.Target;
它必须拆箱,因此 副本 存储在 val
中。您以后所做的任何修改都是在副本上进行的,而不是在盒装 struct
.
上进行的
它与 GCHandle
无关,它是值类型 (struct
s) 在 C# 中的工作方式。这就是为什么建议使值类型不可变。
因为 value
是一个 sturct
并且结构不是引用类型。当你有一个结构实例并且 var b = instanceOfStruct
那么 b
是一个新结构而不是对 instanceOfStruct
的引用。更改 b
中的值不会反映到 instanceOfStruct
。
在您的代码中:
value val = (value)gch.Target;
将创建一个 value
结构的新实例,它与 gch.Target
指向它的结构具有相同的值。更改 val
不会更改 gch.Target
后面的结构。问题是由于 C# 中值类型和引用类型之间的混淆。如果将 value
类型更改为 class 而不是 struct
,那么您将获得所需的结果。您还可以使用 dynamic
修改作为句柄目标的结构:
dynamic val = gch.Target;
val.sz = 6;
我正在尝试了解 C# 中的持久内存,但不知道为什么这段代码没有保留其中一个函数中所做的更改。
using System;
using System.Runtime.InteropServices;
public class Test2
{
public struct value
{
public int sz;
}
public static void Main(string[] args)
{
one foo1 = new one(one_full);
two foo2 = new two(two_full);
make_calls(foo1, foo2);
}
public delegate void one(IntPtr ctx);
public static void one_full(IntPtr ctx)
{
/* set sz and see if persists */
GCHandle gch = GCHandle.FromIntPtr(ctx);
value val = (value)gch.Target;
val.sz = 6;
Console.WriteLine("Changed sz to be 6");
}
public delegate void two(IntPtr ctx);
public static void two_full(IntPtr ctx)
{
GCHandle gch = GCHandle.FromIntPtr(ctx);
value val = (value)gch.Target;
Console.Write("sz is = ");
Console.WriteLine(val.sz);
}
public static void make_calls(one f_one, two f_two)
{
value test = new value();
test.sz = 0;
IntPtr ptr = GCHandle.ToIntPtr(GCHandle.Alloc(test));
f_one(ptr);
f_two(ptr);
}
}
我知道最后缺少 free 但这只会导致混乱的内存管理....我正在寻找是否有人可以帮助我并解释为什么 sz 不保持为值 6当调用第二个函数时...
运行时的输出为:
Changed sz to be 6
sz is = 0
都是因为value
是一个struct
。
GCHandle.Alloc
需要一个object
参数,所以如果你传递一个struct
,它必须被装箱。
以后使用
value val = (value)gch.Target;
它必须拆箱,因此 副本 存储在 val
中。您以后所做的任何修改都是在副本上进行的,而不是在盒装 struct
.
它与 GCHandle
无关,它是值类型 (struct
s) 在 C# 中的工作方式。这就是为什么建议使值类型不可变。
因为 value
是一个 sturct
并且结构不是引用类型。当你有一个结构实例并且 var b = instanceOfStruct
那么 b
是一个新结构而不是对 instanceOfStruct
的引用。更改 b
中的值不会反映到 instanceOfStruct
。
在您的代码中:
value val = (value)gch.Target;
将创建一个 value
结构的新实例,它与 gch.Target
指向它的结构具有相同的值。更改 val
不会更改 gch.Target
后面的结构。问题是由于 C# 中值类型和引用类型之间的混淆。如果将 value
类型更改为 class 而不是 struct
,那么您将获得所需的结果。您还可以使用 dynamic
修改作为句柄目标的结构:
dynamic val = gch.Target;
val.sz = 6;