是固定的静态类成员

本文关键字:静态类 成员 | 更新日期: 2023-09-27 18:20:29

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

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

环境是VS 2008,Compact Framework 3.5。

是固定的静态类成员

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

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

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

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

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

是。你需要固定对象。

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

我不认为静态修改器意味着它最终会在内存中有一个静态位置是错误的,但更大的问题是没有API允许您在不固定对象的情况下获取内存地址。无论是否被GC移动。

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

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

是的。如果指针没有固定,GC可以自由移动该内存,因此您可能有悬挂的C++指针,指向一些无效的,或者更糟的是,根本不是它们的内存。

此外,应澄清"共享"一词。如果分配并传递给非托管内存,而非托管内存将其复制到某个位置,则可以避免经常固定它们。取决于将控制权传递给非托管环境后会发生什么。

编辑

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