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