public class Foo
{
public void Draw() // Called 60 times per second
{
spriteBatch.Draw(new Vector2(x, y), null, Color.White);
}
private float x, y;
}
特别是,我想知道new Vector2(x, y)
电话是否正在产生垃圾。
我的理解是,由于Vector2
是值类型,并且未被存储为引用类型的成员,因此将在堆栈。因此,只要Draw
方法返回,就应该自动回收它的内存,不会产生垃圾。
这是对的吗?
修改
如果我可以要求进一步澄清Eric Lippert的首发帖子。
问题1)
这取决于被调用函数的第一个形式参数是采用引用类型还是值类型。如果它采用值类型然后否,则此处不会生成垃圾。如果它采用引用类型,那么该值将被加框。
然后如果签名碰巧是这样的:
public void Draw()
{
Vector2 vector = new Vector2(x, y);
spriteBatch.Draw(ref vector, null, Color.White);
}
它会从正在装箱的矢量中生成垃圾吗?
问题2)
仅仅因为它不在堆上并不逻辑上需要它在堆栈上生成。它可能在一个寄存器中。
但我认为存储在寄存器中的行为就像从垃圾收集器的角度存储在堆栈中一样。这是对的吗?
答案 0 :(得分:5)
我想知道
new Vector2(x, y)
电话是否正在产生垃圾。
这取决于被调用函数的第一个形式参数是采用引用类型还是值类型。如果它采用值类型然后否,则此处不会生成垃圾。如果它采用引用类型,那么该值将被加框。
我的理解是,由于Vector2是一个值类型,并且没有存储为引用类型的成员,因此它将在堆栈上创建
仅仅因为它不在堆上并不逻辑上需要它在堆栈上生成。它可能在一个寄存器中。
如果签名需要通过“ref”(使用“ref”或“out”修饰符)传递结构,那么会有任何装箱吗?
没有。你混合了两种参考。 变量的别名的“引用”不是对象:
void D(int q) {}
void D(ref int q) {}
void D(object q) {}
第一种方法D采用整数的副本。第二个D为包含未装箱整数的变量创建别名。第三个D取一个盒装整数。
我假设存储在寄存器中的行为就像从垃圾收集器的角度存储在堆栈中一样。
这不是一个有效的假设。假设已注册或放置在堆栈上的值包含对垃圾收集对象的引用。抖动在其处理已注册引用的权限范围内与堆栈引用不同。例如,假设抖动的寄存器分配算法决定在抖动知道参考将不再被解除引用之后重新使用该寄存器。抖动完全自由,然后告诉垃圾收集器引用已经消失。通过这样做,即使在对象的方法正在执行时,GC线程也可能释放'this'。
抖动当然也可以自由地使用堆栈,但这将是一个更积极的优化。
答案 1 :(得分:3)
正确,Vector2
将存在于相关的堆栈帧上(与Color
一样) - 请注意:因为它没有被ref
传递,所以该值将被复制到Draw
堆栈框架。 Vector2
非常小(64位/ 8字节),这很可能是非问题 - 但只要每个堆栈帧完成Vector2
,内存就会被回收。