什么是固定对象?

我试图find使用ant内存分析器的内存泄漏,我遇到了一个新的术语:

固定对象。

有人可以给我一个很好的和简单的解释这个对象是什么,我怎么能pinn / unpinn对象,并检测谁固定对象?

谢谢

固定对象是不允许移动的对象。 垃圾回收器通常会压缩内存,因为它将所有对象移动到“一个或多个集群”。 这是创造大块的自由空间。

这基本上意味着如果其他人(外部)有一个指向对象的内存地址的指针,这可能指向随机内容 – 随着对象的移动。

固定一个对象告诉GC不要移动它。 这通常是无用的,只有在使用指针时才有意义 – 就像使用PInvoke一样。 有时你需要把一个地址转换成一个结构体(在内存布局的术语中),如果这是在一个类中实现的,那么你必须将其固定。

回答具体问题:

  • 你不能找出谁是固定的。
  • 固定是用FIXED语句完成的。 这只允许在不安全的代码。

检查:

http://msdn.microsoft.com/en-us/library/f58wzh21%28VS.80%29.aspx

固定的对象是垃圾收集器无法移动的对象,这意味着它的地址必须保持不变,因为其他人通常是某个非托pipe代码片段依赖于处于确定内存地址的对象。

垃圾收集器通常可以自由地在内存中重新定位对象。 在托pipe代码中,由于垃圾收集器可以访问所有引用,因此可以将对象自由地重新映射到不同的位置,然后更新对该对象的所有引用,以便对运行的代码透明。 这样,GC有能力更好地组织程序的内存,并在需要时将其压缩。

当一个非pipe理对象与你的代码交互时(在不安全的部分中),当你的代码中有一个指针的时候,可能会出现这样的情况 – 例如,你的代码中正在处理的一段内存一个外部COM调用。 这个内存不能被重新映射,因为COM调用期望对象在一个给定的地址,因此,如果它被移动,GC将没有任何方式来通知COM对象该变化,导致访问违规或更糟。

与非托pipe代码进行通信时使用固定对象。 在托pipe代码中,垃圾收集器可以自由移动内存块,因为它知道所有对内存块的引用,并可以相应地更新这些内存块。

与非托pipe代码(如Win-API)进行通信时,通常会将指向数据或缓冲区的指针作为parameter passing。 如果垃圾收集器可以自由移动这些数据,指针会突然失效。 当指针被传送到非托pipe代码时,GC不能更新指针 – 甚至不知道它在哪里被使用。 为防止内存移动并确保数据停留在非托pipe代码指针已知的位置,可以locking对象。

你可能会固定一个对象的原因是,如果你正在调用非托pipe代码。

垃圾收集器运行时,可能会删除不再需要的对象。 这在堆中留下了空闲空间的“洞”。 GC然后通过将剩余的对象移动到一起以确保可用空间位于一个连续的块中(有点像对硬盘进行碎片整理)来压缩堆。

它还将所有引用(在托pipe代码中)更新为已经作为压缩的一部分移动的任何对象。

如果你正在使用非托pipe代码(例如一些外部的C ++)并给它一个指向对象的指针,那么GC就没有办法让非托pipe代码知道该对象在运行后已经移动了。 因此,您可能会将与外部代码共享的对象标记为固定,以便您不会遇到指针无效的问题。

为了固定对象,您可以使用fixed关键字:

fixed语句阻止垃圾收集器重新定位一个可移动的variables。 固定语句只允许在不安全的情况下使用。

我之前见过的一个例子是把一个long值分解成字节,这样它就可以被编码成一个序列密钥。 这是在一个不安全的环境下完成的,以获得指针。 由于在获取单个字节的过程中发生垃圾收集,间歇性错误开始发生。 值将被重新定位,我们留下了一半正确的字节,半垃圾字节。

我们的解决scheme是使用BitConverter类。 如果您查看BitConverter类的底层代码,您将看到它使用fixed关键字来固定字节数组,同时从variables中获取字节。

固定对象是在内存中具有设置位置的对象。

垃圾收集器通常会压缩托pipe堆,这会更改内存中对象的位置。 如果你有一些非托pipe代码引用了你创build的一些C#对象,你可能希望能够完全引用内存位置。 固定对象使您可以确定地做到这一点。

您可以使用fixed语句创build它们: http : //msdn.microsoft.com/en-us/library/f58wzh21%28VS.80%29.aspx

从msdn得到“固定的对象是垃圾收集器不能在内存中移动的对象”

http://msdn.microsoft.com/en-us/library/x2tyfybc(VS.71).aspx