简体   繁体   English

为什么使用Object Initializer保持对象存活?

[英]Why does using an Object Initializer keep an object alive?

I recently came across this SO article and tweaked it for my scenario which follows: 我最近遇到了这篇SO文章并根据我的场景进行了调整:

using System;
using System.Collections.Generic;

namespace ConsoleApplication18
{
    class Program
    {
        static void Main(string[] args)
        {
            Manager mgr = new Manager();
            var obj = new byte[1024];

            var refContainer = new RefContainer();
            refContainer.Target = obj;

            obj = null;

            mgr["abc"] = refContainer.Target;

            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            Console.WriteLine(mgr["abc"] != null); // true (still ref'd by "obj")

            refContainer = null;

            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            Console.WriteLine(mgr["abc"] != null); // false (no remaining refs)           
        }
    }

    class RefContainer
    {
        public object Target { get; set; }
    }

    class Manager
    {
        Dictionary<string, WeakReference> refs =
        new Dictionary<string, WeakReference>();
        public object this[string key]
        {
            get
            {
                WeakReference wr;
                if (refs.TryGetValue(key, out wr))
                {
                    if (wr.IsAlive)
                        return wr.Target;
                    refs.Remove(key);
                }
                return null;
            }
            set
            {
                refs[key] = new WeakReference(value);
            }
        }
    }
}

Running this program gives the following expected result: 运行此程序会产生以下预期结果:

True
False
Press any key to continue . . .

However change this: 然而改变这个:

var refContainer = new RefContainer();
refContainer.Target = obj;

To this (using Object Initializer syntax): 为此(使用Object Initializer语法):

var refContainer = new RefContainer() { Target = obj };

Gives the following output: 给出以下输出:

True
True
Press any key to continue . . .

What's going on here? 这里发生了什么? Why would lifetime of the reference be different just because of using Object Initializer? 为什么引用的生命周期因使用Object Initializer而不同?

Why would lifetime of the reference be different just because of using Object Initializer? 为什么引用的生命周期因使用Object Initializer而不同?

I can't actually reproduce your problem anyway, but I suspect it's because this: 无论如何我无法重现你的问题,但我怀疑是因为这个:

var refContainer = new RefContainer() { Target = obj };

is equivalent to: 相当于:

var tmp = new RefContainer();
tmp.Target = obj;
var refContainer = tmp;

... so you end up with an extra reference to the object on the stack. ...所以你最终得到了对堆栈上对象的额外引用。 Now when running not under the debugger, I'd expect the GC to notice that that stack location is never read again, and allow the object to be garbage collected - but as you're running under the debugger, the GC is more conservative, and I suspect it treats all stack variables as GC roots. 现在在调试器下不运行时,我期望的GC注意到,该堆栈位置是永远不会再次读取,并允许垃圾回收的对象-但正如你在调试器下运行时,GC是比较保守的,我怀疑它将所有堆栈变量视为GC根。

That's just a guess though - without being able to reproduce it anyway, it's hard to say for sure. 这只是一个猜测 - 无论如何都无法重现它,很难肯定地说。

EDIT: Your assignments of obj = null; 编辑:你的obj = null;分配obj = null; and refContainer = null; refContainer = null; are pointless under non-debug mode; 在非调试模式下毫无意义; because the variables aren't read after that point anyway, the GC ignores them as GC roots. 因为无论如何都不会在该点之后读取变量,GC会将它们忽略为GC根。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM