在C#的背景下:
我们假设以下代码......
public class Foo
{
MrObject object1;
MrObject object2;
MrObject object3;
MrObject object4;
MrStruct struct1;
MrStruct struct2;
MrStruct struct3;
MrStruct struct4;
int i;
public Foo()
{
object1 = new MrObject(1); /// Alpha
object2 = new MrObject(2); /// Bravo
object3 = new MrObject(3); /// Charlie
object4 = new MrObject(4); /// Delta
i = 1;
InitializeComponent(); // POINT A
ByValByRef(object1, ref object2);
}
public void ByValByRef(MrObject o1, ref MrObject o2)
{
o1.foo = 5; // POINT B
o1 = object3; // POINT C
o2.foo = 6; // POINT D
o2 = object4; // POINT E
return;
}
我的理解是在// POINT A - 您已创建了四个MyObject实例。这四个实例存在于堆中。 - 您有四个对这些实例的引用。 问题1:他们住在哪里?
我的理解是在// POINT B - 您创建了一个名为'o1'的'Alpha'的新引用。该引用被添加到堆栈中并存在于堆栈中。当方法返回时,该引用被删除 - 你有一个名为'o2'的引用。 问题2:这是一个新的引用,它被添加到堆栈并存在于堆栈中并引用了'object2'引用?或者'o2'只是在代码中维护的别名(而不是在内存中),实际上在内存中只有一个引用'Bravo'称为'object2',当这个代码实际执行时,'o2.foo'被处理作为'object2.foo'?
答案 0 :(得分:1)
我的理解是,在// POINT A - 你创造了四个 MyObject的实例。这四个实例存在于堆中。
右。已在堆上为每个对象分配内存。
您有四个对这些实例的引用。问题1:他们在哪里 住?
创建对象时,您将每个对象分配(引用)到Foo
对象上的不同字段。这些字段“存活”在为Foo
对象分配的内存中,这几乎肯定在堆上的某个位置。
我的理解是在// POINT B - 你创造了一个新的 引用名为'o1'的'Alpha'。该参考被添加到并生活 在堆栈上。当方法返回时,该引用将被删除。
是的,在POINT B,参数o1
还存储对作为参数传递的MrObject
的引用。 o1
住在短期商店,这通常是“堆栈”。当方法结束时,用于o1
的短期存储空间将可供其他用途使用,垃圾收集器将不再将o1
视为已知的实时根。
你有一个名为'o2'的引用。问题2:这是一个新的参考 添加到堆栈并生活在堆栈上并引用'object2' 参考?或者'o2'只是代码中维护的别名(而不是代码) 内存)实际上在内存中仍然只有一个引用 'Bravo'称为'object2',当这段代码实际执行时, 'o2.foo'被视为'object2.foo'?
现在我们来看你问题的棘手部分。 o2
是另一种参考。它不是对堆上对象的引用,而是实际上是object2
对象上Foo
字段的别名(如您所推测的)。 o2
仍占据短期商店的空间,因为它仍然是方法的论据。
顺便说一下,“Bravo
内存中只有一个引用”并不是你应该担心的。 可从已知GC根访问的引用决定了是否可以安全地收集特定对象。