[您没有指望的垃圾收集中有[[two
您好,我在这里有不了解为何达到断点的代码(请参见注释)。
这是我不知道还是不正确理解的Microsoft bug?
该代码已在Debug中测试,但我认为它不应更改任何内容。
注意:您可以直接在控制台应用程序中测试代码。
仅用于信息...在超级猫的回答之后,我用建议的解决方案修复了我的代码,它很好用:-) !!!不好的事情是静态字典的使用以及它所具有的性能,但是它可以工作。...几分钟后,我意识到SuperCat会给我所有更好的提示,以解决静态字典,我做到了。代码示例是:
样品...
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace WeakrefBug
{
// **********************************************************************
class B : IDisposable
{
public static List<B> AllBs = new List<B>();
public B()
{
AllBs.Add(this);
}
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
AllBs.Remove(this);
disposed = true;
}
}
~B() { Dispose(false); }
}
// **********************************************************************
class A
{
WeakReference _weakB = new WeakReference(new B());
~A()
{
B b = _weakB.Target as B;
if (b == null)
{
if (B.AllBs.Count == 1)
{
Debugger.Break(); // b Is still referenced but my weak reference can't find it, why ?
}
}
else { b.Dispose(); }
}
}
// **********************************************************************
class Program
{
static void Main(string[] args)
{
A a = new A();
a = null;
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
}
}
// **********************************************************************
}
版本已更正:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace WeakrefBug // Working fine with ConditionalWeakTable
{
// **********************************************************************
class B : IDisposable
{
public static List<B> AllBs = new List<B>();
public B()
{
AllBs.Add(this);
}
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
AllBs.Remove(this);
disposed = true;
}
}
~B() { Dispose(false); }
}
// **********************************************************************
class A
{
private static readonly System.Runtime.CompilerServices.ConditionalWeakTable<A, B> WeakBs = new ConditionalWeakTable<A, B>();
public A()
{
WeakBs.Add(this, new B());
}
public B CreateNewB()
{
B b = new B();
WeakBs.Remove(this);
WeakBs.Add(this, b);
return b;
}
~A()
{
B b;
WeakBs.TryGetValue(this, out b);
if (b == null)
{
if (B.AllBs.Count == 1)
{
Debugger.Break(); // B Is still referenced but my weak reference can't find it, why ?
}
}
else { b.Dispose(); }
}
}
// **********************************************************************
class Program
{
static void Main(string[] args)
{
A a = new A();
WeakReference weakB = new WeakReference(a.CreateNewB()); // Usually don't need the internal value, but only to ensure proper functionnality
a = null;
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
Debug.Assert(!weakB.IsAlive);
}
}
// **********************************************************************
}
带有ConditioalWeakTable的代码,其中包含SuperCat技巧(非常感谢他!)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace WeakrefBug // Working fine with non static ConditionalWeakTable - auto cleanup
{
// **********************************************************************
class B : IDisposable
{
public static List<B> AllBs = new List<B>();
public B()
{
AllBs.Add(this);
}
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
AllBs.Remove(this);
disposed = true;
}
}
~B() { Dispose(false); }
}
// **********************************************************************
class A
{
private ConditionalWeakTable<object, object> _weakBs = null;
public A()
{
}
public B CreateNewB()
{
B b = new B();
if (_weakBs == null)
{
_weakBs = new ConditionalWeakTable<object, object>();
_weakBs.Add(b, _weakBs);
}
_weakBs.Remove(this);
_weakBs.Add(this, b);
return b;
}
internal ConditionalWeakTable<object, object> ConditionalWeakTable // TestOnly
{
get { return _weakBs; }
}
~A()
{
object objB;
_weakBs.TryGetValue(this, out objB);
if (objB == null)
{
if (B.AllBs.Count == 1)
{
Debugger.Break(); // B Is still referenced but my weak reference can't find it, why ?
}
}
else
{
((B)objB).Dispose();
}
}
}
// **********************************************************************
class Program
{
static void Main(string[] args)
{
A a = new A();
WeakReference weakB = new WeakReference(a.CreateNewB()); // Usually don't need the internal value, but only to ensure proper functionnality
WeakReference weakConditionalWeakTable = new WeakReference(a.ConditionalWeakTable);
a = null;
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
Debug.Assert(!weakB.IsAlive);
Debug.Assert(!weakConditionalWeakTable.IsAlive);
}
}
// **********************************************************************
}
[CitizenInsane的以下问题...我不记得是为什么做我做的事...我找到了样本,但当时不确定我的意图。我试图弄清楚,并附带了以下代码,虽然我的意思很清楚,但仍然不记得我的原始需求。对不起???
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace WeakrefBug // Working fine with ConditionalWeakTable
{
// **********************************************************************
class B : IDisposable
{
public static List<B> AllBs = new List<B>();
public B()
{
AllBs.Add(this);
}
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
AllBs.Remove(this);
disposed = true;
}
}
~B() { Dispose(false); }
}
// **********************************************************************
class A
{
private ConditionalWeakTable<object, object> _weakBs = null;
private WeakReference _weakB = null;
public A()
{
_weakBs = new ConditionalWeakTable<object, object>();
B b = new B();
_weakB = new WeakReference(b);
_weakBs.Add(b, _weakB);
}
public B B
{
get
{
return _weakB.Target as B;
}
set { _weakB.Target = value; }
}
internal ConditionalWeakTable<object, object> ConditionalWeakTable // TestOnly
{
get { return _weakBs; }
}
~A()
{
B objB = B;
if (objB == null)
{
if (B.AllBs.Count == 1)
{
Debugger.Break(); // B Is still referenced but my weak reference can't find it, why ?
}
}
else
{
((B)objB).Dispose();
}
}
}
// **********************************************************************
class Program
{
static void Main(string[] args)
{
Test1();
Test2();
}
private static void Test1()
{
A a = new A();
WeakReference weakB = new WeakReference(a.B); // Usually don't need the internal value, but only to ensure proper functionnality
WeakReference weakConditionalWeakTable = new WeakReference(a.ConditionalWeakTable);
a = null;
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
Debug.Assert(B.AllBs.Count == 0);
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
Debug.Assert(!weakB.IsAlive); // Need second pass of Collection to be collected
Debug.Assert(!weakConditionalWeakTable.IsAlive);
}
private static void Test2()
{
A a = new A();
WeakReference weakB = new WeakReference(a.B);
B.AllBs.Clear();
a.B = null;
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
Debug.Assert(!weakB.IsAlive); // Need second pass of Collection to be collected
}
}
// **********************************************************************
}
如果对象的终结器有必要使用WeakReference
有时令人讨厌的局限性是,如果不存在对WeakReference
itself]的强根引用,WeakReference
可能会失效,即使trackResurrection
构造函数参数也可能发生这种情况是true
,并且即使WeakReference
的目标已扎根]。此行为源于以下事实:WeakReference
具有不受管的资源(GC句柄),并且如果WeakReference
的终结器没有清理GC句柄,则它将永远不会被清理,并且会构成内存泄漏。WeakReference
对象,则该对象必须做出某些规定以确保强烈引用那些对象。我不确定实现此目标的最佳模式是什么,但是.net 4.0中添加的ConditionalWeakTable<TKey,TValue>
可能有用。它有点像Dictionary<TKey,TValue>
,除了只要表本身被强力引用并且给定键被强力引用,其对应的值也将被视为强引用。请注意,如果ConditionalWeakTable
保留将X链接到Y,并将Y链接到表的条目,则只要保留X或Y,表也将保留。
[您没有指望的垃圾收集中有[[two
B.Dispose()方法中也存在一个错误,当客户端代码显式放置该对象时,它将无法正确计算B实例。您尚未遇到该错误。
没有合理的方法来修复此代码。此外,它还测试了已经由CLR提供的严格保证支持的东西。只需将其删除。
_weakB
与对象a
同时可用于垃圾回收。您这里没有顺序保证,因此很有可能_weakB
在对象a
之前完成。访问A的终结器中的_weakB
是危险的,因为您不知道_weakB
的状态。我猜想在您的情况下,它已经完成,并且导致它为.Target
返回null。
[您没有指望的垃圾收集中有[[two
_weakB
与对象a
同时可用于垃圾回收。您这里没有顺序保证,因此很有可能_weakB
在对象a
之前完成。访问A的终结器中的_weakB
是危险的,因为您不知道_weakB
的状态。我猜想在您的情况下,它已经完成,并且导致它为.Target
返回null。