C# 为什么WeakReference.IsAlive会变成假的?
作为后续行动,我有以下代码:C# 为什么WeakReference.IsAlive会变成假的?,c#,.net,garbage-collection,finalizer,C#,.net,Garbage Collection,Finalizer,作为后续行动,我有以下代码: using System; using System.Runtime.InteropServices; namespace ConsoleApplication1 { class Program { class Child { public override string ToString() { return "I am a child
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
class Child
{
public override string ToString()
{
return "I am a child!";
}
~Child()
{
Console.WriteLine("~Child called");
}
}
class Test
{
readonly object _child;
readonly WeakReference _ref;
readonly GCHandle _gch; // GCHandle is a value type, so it's safe
public Test()
{
_child = new Child();
_ref = new WeakReference(_child);
_gch = GCHandle.Alloc(_child);
}
// ...
public void DoTest()
{
lock (_child)
{
Console.WriteLine("DoTest called, child: " + _child.ToString() + ", is alive: " + _ref.IsAlive);
}
}
~Test()
{
Console.WriteLine("~Test starts");
DoTest();
_gch.Free();
Console.WriteLine("~Test ends");
}
}
static void Main(string[] args)
{
var test = new Test();
test.DoTest();
test = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
System.Threading.Thread.Sleep(1000);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
Console.ReadLine();
}
}
}
输出:
DoTest called, child: I am a child!, is alive: True
~Test starts
DoTest called, child: I am a child!, is alive: False
~Test ends
~Child called
多斯特喊道,孩子:我是个孩子!,他还活着:真的
~z~测试开始了
多斯特喊道,孩子:我是个孩子!,他还活着:错
~z~测试结束
~z~孩子打电话来了
问题:为什么
WeakReference.IsAlive
for\u child
在~Test()
内变成false
,而\u child
对象仍然被GCHandle.Alloc嗯,我记得从finalizer访问“类实例变量”不是一个好主意,因为它们可能处于“随机”状态这基本上意味着WeakReference终结器将在类终结器之前被调用。
有一个专用于调用Finalize的特殊运行时线程
方法。当freachable队列为空时(通常为
这个线程休眠。但当条目出现时,该线程将被唤醒,
从队列中删除每个条目,并调用每个对象的Finalize
方法。因此,您不应该在Finalize中执行任何代码
方法,该方法对执行
代码例如,避免访问
最终确定方法。
如果您确定了WeakReference,您可以获得更有意义的结果:
public Test()
{
_child = new Child();
_ref = new WeakReference(_child);
_gch = GCHandle.Alloc(_child);
_test = GCHandle.Alloc(_ref);
}
如果让GC知道WeakReference类本身目前无法收集,则可以得到相同的结果,例如:
static void Main(string[] args)
{
var test = new Test();
var win = new WeakReference(test._child);
test._ref = win;//new WeakReference(test._child);
test.DoTest();
test = null;
}
WeakReference中的实际代码:
~WeakReference() {
IntPtr old_handle = m_handle;
if (old_handle != IntPtr.Zero) {
if (old_handle == Interlocked.CompareExchange(ref m_handle, IntPtr.Zero, old_handle))
GCHandle.InternalFree(old_handle);
}
}
您可以看到,一旦它的终结器运行,它就会释放句柄,将其设置为零&IsAlive现在将报告false。但引用本身实际上是活动的。就是这样,你把它搞定了WeakReference
在Test
之前得到GC'ed,这就是它返回false
I recon的原因,尽管\u子项仍处于活动状态。固定WeakReference
使其返回true
。是的,这几乎是正确的,但如果您看到前面的问题和答案:WeakReference本身不是垃圾收集的(至少不是在那个时候),它的终结器被调用(这使它返回false)。通过固定它,您本质上说终结器不能为WeakReference.Right运行。为了安全起见,我只需在DoTest()中执行lock({}
,因为GCHandle
是一种值类型。您从哪个.NET版本获得Finalize
代码?对我来说,这是一个内部通话。我在4.5.2左右。我从这里开始:似乎是4.0