什么是固定物?

sag*_*gie 45 c# memory garbage-collection

我试图使用蚂蚁内存分析器找到内存泄漏,我在一个新术语中遇到过:

固定物体.

有人可以给我一个关于这个对象是什么的简单而简单的解释,我如何pinn/Unpinn对象,并检测谁固定对象?

谢谢

小智 52

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

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

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

回答具体问题:

  • 你无法找出谁固定了一个对象.
  • 固定是使用FIXED语句完成的.这只能在不安全的代码中使用.

校验:

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

  • 它不需要是不安全的.如您所见:Buffer = new byte [imageSize]; GCHandle gCBuffer = GCHandle.Alloc(Buffer,GCHandleType.Pinned); (12认同)
  • 但是,它确实需要完全信任,这相当于不安全的代码。 (2认同)

Jor*_*oba 19

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

通常,垃圾收集器可以自由地在内存中重定位对象.在托管代码,作为垃圾收集器具有访问所有的引用的能力,因此可以自由地重新映射的对象到不同的位置,然后更新该对象的所有引用,使得过程是透明的运行代码.这样,GC就能够更好地组织程序的内存并在需要时压缩它.

当一个非管理对象是与你的代码进行交互(在不安全的部分)的情况下可能出现的,其中有一个指针某处一块代码的 - 例如,一块内存在代码正被处理的处理外部COM调用.此内存无法重新映射,因为COM调用期望对象位于给定地址中,因此,如果它被移动,GC将无法以任何方式通知COM对象该更改,从而导致访问违规或更糟.


And*_*bel 6

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

与非托管代码(例如Win-API)通信时,通常会将指向数据或缓冲区的指针作为参数传递.如果垃圾收集器可以自由移动该数据,则指针会突然变为无效.当指针转移到非托管代码时,GC无法更新指针 - 甚至不知道它的使用位置.为了防止内存移动并确保数据保留在非托管代码指针所知的位置,可以固定对象.


Pao*_*olo 6

您可以固定对象的原因是您是否正在调用非托管代码.

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

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

如果您正在使用非托管代码的工作(例如,一些外部的C++),并给它一个指向对象,也没有办法为GC告诉它运行后的对象移动的非托管代码.因此,您可能会将与外部代码共享的对象标记为固定,这样您就不会遇到指针变为无效的问题.


Ric*_*ber 5

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

fixed语句阻止垃圾收集器重定位可移动变量.固定语句仅允许在不安全的上下文中使用.

我之前看到的一个例子是将长值分解为字节,以便将其编码为串行密钥.这是在不安全的上下文中完成的,以获取指针.由于垃圾收集将在获取单个字节的过程中途发生,因此开始发生间歇性错误.该值将被重新定位,我们留下了一半的正确字节,一半垃圾字节.

我们的解决方案是使用BitConverter类.如果你看一下BitConverter类的底层代码,你会看到它使用fixed关键字来固定字节数组,同时从变量中获取字节.


Jon*_*onC 5

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

通常垃圾收集器会压缩托管堆,这会改变对象在内存中的位置。如果您有一些非托管代码引用您创建的某个 C# 对象,您可能希望能够绝对引用内存位置。固定对象使您可以确定地执行此操作。

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