我在想,
班级的实例在堆上。 (其中的值类型也在堆中)。
但相反案例呢?
有一个问题 here ,但未提及任何GC
相关信息。
那么 - GC如何处理这种情况?
public struct Point
{
object o ;
public int x, y;
public Point(int p1, int p2)
{
o = new Object();
x = p1;
y = p2;
}
}
答案 0 :(得分:7)
Point
包含对堆上对象的引用。只要该引用不再存在Point
的副本,这将有资格收集。注意到:
Point p1 = new Point(1,2);
Point p2 = p1;
是2个副本,每个副本都引用堆上的相同对象。如果这些点作为字段存储在对象的某个地方,那么显然对象的生命周期至少与具有这些字段的对象一样长。如果这些点只是堆栈上的变量,那么它会变得更复杂,因为GC可能会考虑变量是否再次 read 。如果不是,则变量可能不会有效存在(或者:可能)。
路径可以是非常间接的,但它基本上归结为:GC可以从GC根源开始到达对象。
答案 1 :(得分:3)
GC确实在
中搜索对象根在你的情况下,结构通常位于线程堆栈内部,因此被搜索。如果它是盒装的,那么它作为伪对象驻留在托管堆上。但是你可以放心,这个东西被GC正确计算了。因为它确实包含一个对象,所以它不再是一个blittable类型,不能通过PInvoke传递给非托管代码。
PInvokes存在一个问题,如果你向它传递一个结构,它将被GC,即使无法进行的调用仍在进行中,它只能在发布版本中实现,因为对于调试版本,变量的生命周期会延长到方法留下。在发布模式下,GC可以更积极地收集。
<强> EDIT1:强> 作为类对象中的成员的结构不是特例。 GC将检查嵌入式结构中的类引用的所有类字段。
答案 2 :(得分:0)
结构类型的存储位置最好被认为是与Duck®牌胶带固定在一起的存储位置的集合;固定在一起的存储位置的性质将是结构的性质。如果结构存储在堆栈中,其字段将存储在堆栈中;如果结构存储在堆对象字段中,则其字段将存储为该堆对象的一部分;如果一个结构存储在一个可变的存储位置,它的字段(公共或私有)将是可变的(即使结构不提供变异,将一个结构复制到另一个结构将通过用相应的方法覆盖它的字段来改变它前者的领域)。如果结构存储在不可变存储位置,则其所有字段都将是不可变的。
如果以这种方式查看事物,很容易理解结构的GC行为与通过简单地用单独的字段替换结构所获得的GC行为基本相同(行为的唯一重要位置) “不寻常”是数组,因为通常数组槽只包含一个项而不是一个字段集合;没有非结构等同于结构类型的数组。)