是否固定了静态类成员?

时间:2015-11-03 20:32:23

标签: c# static

我有一个C#类,有一个静态的ImageList对象。此图像列表将与我的应用程序中的多个表单上的各种ListView标头(通过SendMessage ... HDM_SETIMAGELIST)共享。

虽然我知道静态对象不符合垃圾收集条件,但我不清楚它们是否也不符合垃圾收集器的重定位(压缩)条件。我是否还需要固定此对象,因为它与非托管代码共享,例如,使用GCHandle.Alloc?

环境是VS 2008,Compact Framework 3.5。

3 个答案:

答案 0 :(得分:2)

实例本身不是静态的。参考是。如果您使引用为空,则实例将符合GC的条件。在内部,所有静态实例都是通过固定数组的固定句柄引用。即该实例由运行时隐式固定。

如果您查看声明为静态成员的实例的GCroot,您将看到如下内容:

HandleTable:
    008113ec (pinned handle)
    -> 032434c8 System.Object[]
    -> 022427b0 System.Collections.Generic.List`1[[System.String, mscorlib]]

如果使静态引用为空,则固定数组中的相应条目也会为空。

现在,这些显然是实施细节,因此它们可能会发生变化。

答案 1 :(得分:0)

  

我是否还需要固定此对象,因为它与非托管共享   代码,比方说,使用GCHandle.Alloc?

是。如果指针没有被固定,GC可以自由移动那个内存,所以你可能有悬空的C++指针,指向一些无效的,或更糟的是,根本没有内存。

此外,应澄清“共享”一词。如果你分配并传递给非托管内存,将其复制到某个地方,你可以避免不断地固定它们。取决于将控制权交给非托管环境后会发生什么。

编辑

即使考虑到@Brian的有趣答案,我仍然会选择固定指针。为了在代码中明确指出固定指针的概念,避免在将来的代码维护中出现任何可能的错误并保持清晰。

答案 2 :(得分:0)

是。你需要固定物体。

虽然引用是静态的,也就是说,您可以从您的成员的任何地方访问此位置,它的引用仍然是GC句柄。也就是说,它有资格进行垃圾收集(和/或压缩),但它当然永远不会发生。

我认为静态修饰符意味着它最终会在内存中有一个静态位置并不一定是错的,但更大的问题是没有API可以让你在没有固定对象的情况下获取内存地址。是否被GC移动。

此外,每个AppDomain(非进程)的每个静态成员都是unqiue。同一个静态成员可以存在于同一进程的不同内存位置,并且可以在AppDomain卸载时进行垃圾回收。这是我承认的边缘情况,但即使可以在没有钉扎的情况下完成,也没有钉住对象的真正优势。