Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么WeakReference.IsAlive会变成假的?_C#_.net_Garbage Collection_Finalizer - Fatal编程技术网

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