我试图使用蚂蚁内存分析器找到内存泄漏,我在一个新术语中遇到过:
固定物品。
有人可以给我一个好的&关于这个对象是什么的简单解释,我如何pinn / Unpinn对象,并检测谁固定对象?
由于
答案 0 :(得分:51)
固定对象是不允许移动的对象。垃圾收集器通常压缩内存,因为它将所有对象移动到“一个或多个集群”。这是为了创造大块的自由空间。
这基本上意味着如果其他人(外部)有一个指向对象内存地址的指针,这可能指向随机内容 - 因为对象已移动。
固定一个对象告诉GC不要移动它。这通常是无用的,只有在使用指针时才有意义 - 就像使用PInvoke时一样。有时您需要将地址转换为结构(在内存布局术语中),如果在类中实现,则必须将其固定。
回答具体问题:
检查:
http://msdn.microsoft.com/en-us/library/f58wzh21%28VS.80%29.aspx
答案 1 :(得分:19)
固定对象是垃圾收集器无法移动的对象,意味着它的地址必须保持不变,因为其他人(通常是某些非托管代码)依赖于对象位于确定的内存地址。
通常,垃圾收集器可以自由地在内存中重定位对象。在托管代码中,由于垃圾收集器能够访问所有引用,因此它可以自由地将对象重新映射到其他位置,然后更新对该对象的所有引用,以使该进程对正在运行的代码透明。这样,GC就能够更好地组织程序的内存并在需要时压缩它。
当一个非托管对象与你的代码进行交互时(在不安全的部分中),可能会出现一个指针位于某段代码的位置 - 例如,代码中的一段内存,即由外部COM调用处理。此内存无法重新映射,因为COM调用期望对象位于给定地址中,因此,如果它被移动,GC将无法以任何方式通知COM对象该更改,从而导致访问违规或更糟。
答案 2 :(得分:6)
与非托管代码通信时使用固定对象。在托管代码中,垃圾收集器可以自由移动内存块,因为它知道对内存块的所有引用,并可以相应地更新它们。
与非托管代码(例如Win-API)通信时,指向数据或缓冲区的指针通常作为参数传递。如果垃圾收集器可以自由移动该数据,则指针会突然变为无效。当指针转移到非托管代码时,GC无法更新指针 - 甚至不知道它的使用位置。为了防止内存移动并确保数据保留在非托管代码指针所知的位置,对象可以固定。
答案 3 :(得分:6)
您可以固定对象的原因是您正在调用非托管代码。
当垃圾收集器运行时,它可能会删除不再需要的对象。这在堆中留下了“空洞”的自由空间。然后GC通过将剩余的对象移动到一起来压缩堆,以确保可用空间位于一个连续块中(有点像对硬盘进行碎片整理)。
它还将所有引用(在托管代码中)更新为在压缩过程中移动的任何对象。
如果您正在处理非托管代码(例如某些外部C ++)并为其指定一个对象,则GC无法告知非托管代码该对象在运行后已移动。因此,您可以将与外部代码共享的对象标记为固定,这样就不会出现指针变为无效的问题。
答案 4 :(得分:5)
为了固定对象,您可以使用fixed关键字:
固定语句阻止了 垃圾收集器搬迁 可变量。固定的声明 只允许不安全 上下文。
我之前见过的一个例子是将长值分解为字节,以便将其编码为串行密钥。这是在unsafe上下文中完成的,以获取指针。由于垃圾收集将在获取单个字节的过程中途发生,因此开始发生间歇性错误。该值将被重新定位,我们留下了一半正确的字节,一半垃圾字节。
我们的解决方案是使用BitConverter类。如果你看一下BitConverter类的底层代码,你会看到它使用fixed关键字来固定字节数组,同时从变量中获取字节。
答案 5 :(得分:4)
固定对象是在内存中具有设置位置的对象。
通常,垃圾收集器会压缩托管堆,从而更改内存中对象的位置。 如果你有一些非托管代码引用你创建的某个C#对象,你可能希望能够绝对引用内存位置。 固定对象使您可以确定地执行此操作。
您可以使用fixed
语句创建它们:
http://msdn.microsoft.com/en-us/library/f58wzh21%28VS.80%29.aspx
答案 6 :(得分:2)
从msdn得到它 “固定对象是垃圾收集器无法在内存中移动的对象”
http://msdn.microsoft.com/en-us/library/x2tyfybc(VS.71).aspx