本文介绍了为什么WeakReference.IsAlive变为假?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为后续this问题,我有以下的code:

As a follow-up to this question, I have the following code:

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

的问题:为什么 WeakReference.IsAlive _child 成为〜测试(),而 _child 的对象仍是固定打倒 GCHandle.Alloc

The question: why does WeakReference.IsAlive for _child become false inside ~Test(), while the _child object is still pinned down with GCHandle.Alloc?

推荐答案

嗯,我记得从终结访问类的实例变量是不是一个好主意,因为他们可以在随机的状态? 这基本上意味着WeakReference的终结将你的类释放之前调用。

Well, I remember that accessing "class instance variables" from finalizer is not a good idea, as they could be in "random" state? This basically means that WeakReference finalizer will be called before your class finalizer.

有一个特殊的运行线程专门调用的Finalize  的方法。当freachable队列为空(这通常是  情况下),这个线程处于休眠状态。但是,当项目出现,这线程被唤醒,  从队列中删除的每个条目,并调用每个对象的Finalize  方法。正因为如此,你不应该在一个finalize执行任何code  方法,使有关对正在执行的线程的任何假设  code。 例如,避免在访问线程本地存储  最终确定的方法。

http://msdn.microsoft.com/en-us/magazine/ bb985010.aspx

如果你拖住你了WeakReference,你可以得到更多有意义的结果:

If you pin down your WeakReference, you can get more meaningful results:

    public Test()
    {
        _child = new Child();
        _ref = new WeakReference(_child);
        _gch = GCHandle.Alloc(_child);
        _test = GCHandle.Alloc(_ref);

    }

您可以得到相同的结果,如果你让GC知道的WeakReference类的本身不能被收集了,因为这样的:

You can get the same results if you let the GC know that WeakReference class ITSELF can't be collected for now, as such:

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的实际code:

The actual code from 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现在报告虚假。引用本身其实是活的,但。

YOu can see that it releases the handle once it's finalizer has been run, sets it zero & IsAlive will report false now. The reference itself is actually alive though.

这篇关于为什么WeakReference.IsAlive变为假?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-18 07:08