Pay*_*aya 8 c# garbage-collection memory-management weak-references
我在班上使用WeakReference<T>(短弱参考)跟踪一个对象Foo.这个类有一个析构函数,我需要在其中访问该跟踪对象.我跟踪的对象也在跟踪Foo使用WeakReference<Foo>.
所以现在我想知道,究竟什么时候"归零"了WeakReference呢?WeakReference在任何终结器运行之前,所有这些都会被取消,或者在它们跟踪的对象的终结器即将运行之前,它们是否都被取消了?
UPDATE
现在我也想知道是否Mono项目可以为这个项目提供一些启示(链接1,链接2).但我有点担心,也许MS GC并且Mono GC可能会以不同的方式解决这个问题而且不相容.
我想写一个演示程序来演示差异.原来比我指望的更具挑战性.第一个必要的成分是确保终结器线程可以减慢速度,这样你就可以观察到WeakReference.IsAlive的值,而不会有被终结器线程影响的风险.所以我用过:
class FinalizerDelayer {
~FinalizerDelayer() {
Console.WriteLine("Delaying finalizer...");
System.Threading.Thread.Sleep(500);
Console.WriteLine("Delay done");
}
}
Run Code Online (Sandbox Code Playgroud)
然后是一个将成为WeakReference目标的小类:
class Example {
private int instance;
public Example(int instance) { this.instance = instance; }
~Example() {
Console.WriteLine("Example {0} finalized", instance);
}
}
Run Code Online (Sandbox Code Playgroud)
然后是一个程序,它演示了长弱引用之间的区别:
class Program {
static void Main(string[] args) {
var target1 = new Example(1);
var target2 = new Example(2);
var shortweak = new WeakReference(target1);
var longweak = new WeakReference(target2, true);
var delay = new FinalizerDelayer();
GC.Collect(); // Kills short reference
Console.WriteLine("Short alive = {0}", shortweak.IsAlive);
Console.WriteLine("Long alive = {0}", longweak.IsAlive);
GC.WaitForPendingFinalizers();
Console.WriteLine("Finalization done");
GC.Collect(); // Kills long reference
Console.WriteLine("Long alive = {0}", longweak.IsAlive);
Console.ReadLine();
}
}
Run Code Online (Sandbox Code Playgroud)
您必须运行此程序,以便调试器不会影响对象的生命周期.选择Release build并更改调试器设置:Tools + Options,Debugging,General,取消选中"Suppress JIT optimization"选项.
原来对象的终结顺序确实是非确定性的.每次运行程序时,顺序都不同.我们希望FinalizerDelayer对象首先完成,但并不总是这样.我认为这是内置地址空间布局随机化功能的副作用,它使托管代码很难攻击.但经常运行它,你最终会得到:
延迟终结器...
短活着=假
长活=
完成延迟
示例1已完成
示例2已完成终结已
完成
Long alive = False
长话短说:
当对象复活时要小心一个怪癖,当重新创建一个强引用时,将其从可释放队列移回正常堆.这不是我在这个演示程序中探索过的东西,但需要一个很长的弱引用来观察它.你需要长期弱参考的基本原因.
您可以通过一个简单的测试程序自行验证。但我发现类型本身的文档WeakReference比您正在查看的页面更清晰。
特别是,链接页面中称为“短”和“长”的标志trackResurrection在实际的构造函数文档中被调用。该参数的描述如下:
指示何时停止跟踪对象。如果为 true,则在完成后跟踪对象;如果为 false,则仅跟踪对象直到最终确定。
“备注”部分还写道:
如果 trackResurrection 为 false,则会创建一个短弱引用。如果 trackResurrection 为 true,则会创建一个长弱引用。
这证实了当您使用“短”弱引用时,最终确定的对象将不再被该对象跟踪(即成为Target)null,WeakReference但是当您使用“长”弱引用时,它就会被跟踪。
对于这两种弱引用,实际上已被垃圾收集的对象肯定不会再被跟踪(显然)。
一般来说,当终结器线程实际执行其工作时,程序中的其他线程不应该能够观察到对象,因此当属性Target设置为“短”弱引用时的精确时刻null对我来说似乎没有意义。如果程序中的其他线程观察到该值为非空,则终结器尚未运行。如果它观察到它为 null,则终结器已运行。当终结器线程工作时,“其他线程”本身不应该运行,因此就“其他线程”而言,终结本质上应该是原子的。
| 归档时间: |
|
| 查看次数: |
624 次 |
| 最近记录: |