我注意到在使用VS 2013编译32位和64位的.NET 4.0控制台应用程序时,GC的行为不一致。
请看以下代码:
class Test
{
public static bool finalized = false;
~Test()
{
finalized = true;
}
}
在 Main()
中...
var t = new Test();
t = null;
GC.Collect();
GC.WaitForPendingFinalizers();
if (!Test.finalized)
throw new Exception("oops!");
当以64位(调试)模式运行时,这个对象每次都能被成功回收;但是以32位模式运行时,即使我创建更多的对象并等待一段时间,也不能强制回收这个对象(我已经尝试过)。 有没有人有任何想法为什么会这样?这在调试必须处理32位程序集中释放未托管代理数据的代码时给我带来了麻烦。在32位模式下,有很多对象只是一直停留在那里,直到很长一段时间后才被回收(而64位模式不是这样)。 我正在尝试以32位模式调试某些内容,但终结器没有被调用(至少强制未调用)。对象只是停留在那里,永远不会被收集(我可以看到所有的弱引用仍然有值)。在64位模式下,所有的弱引用都被正确地清除,并且所有的终结器都被调用。注意:虽然上面的代码规模非常小,但在32位模式下,我发现许多对象都被卡在垃圾回收中,直到稍后创建更多对象(即使调用“Collect”和“WaitForPendingFinalizers”)。这在64位模式下从未发生过。我有一个用户想知道为什么会有这么多对象没有被收集,这促使我进行了调查,结果发现在64位模式下比32位模式更好。只是想理解为什么。编辑:这里是更好的代码以展示差异:
class Program
{
class Test
{
public static bool Finalized = false;
public int ID;
public Test(int id)
{
ID = id;
}
~Test()
{ // <= Put breakpoint here
Finalized = true;
Console.WriteLine("Test " + ID + " finalized.");
}
}
static List<WeakReference> WeakReferences = new List<WeakReference>();
public static bool IsNet45OrNewer()
{
// Class "ReflectionContext" exists from .NET 4.5 onwards.
return Type.GetType("System.Reflection.ReflectionContext", false) != null;
}
static void Main(string[] args)
{
Console.WriteLine("Is 4.5 or newer: " + IsNet45OrNewer());
Console.WriteLine("IntPtr: " + IntPtr.Size + Environment.NewLine);
Console.WriteLine("Creating the objects ...");
for (var i = 0; i < 10; ++i)
WeakReferences.Add(new WeakReference(new Test(i)));
Console.WriteLine("Triggering collect ...");
GC.Collect();
Console.WriteLine("Triggering finalizers ..." + Environment.NewLine);
GC.WaitForPendingFinalizers();
Console.WriteLine(Environment.NewLine + "Checking for objects still not finalized ...");
bool ok = true;
for (var i = 0; i < 10; ++i)
if (WeakReferences[i].IsAlive)
{
var test = (Test)WeakReferences[i].Target;
if (test != null)
Console.WriteLine("Weak references still exist for Test " + test.ID + ".");
ok = false;
}
if (ok)
Console.WriteLine("All Test objects successfully collected and finalized.");
Console.WriteLine(Environment.NewLine + "Creating more objects ...");
for (var i = 0; i < 10; ++i)
WeakReferences.Add(new WeakReference(new Test(i)));
Console.WriteLine("Triggering collect ...");
GC.Collect();
Console.WriteLine("Triggering finalizers ..." + Environment.NewLine);
GC.WaitForPendingFinalizers();
Console.WriteLine(Environment.NewLine + "Checking for objects still not finalized ...");
ok = true;
for (var i = 0; i < 10; ++i)
if (WeakReferences[i].IsAlive)
{
var test = (Test)WeakReferences[i].Target;
if (test != null)
Console.WriteLine("Weak references still exist for Test " + test.ID + ".");
ok = false;
}
if (ok)
Console.WriteLine("All Test objects successfully collected and finalized.");
Console.WriteLine(Environment.NewLine + "Done.");
Console.ReadKey();
}
}
它在64位系统上可以运行,但不支持32位。在我的系统上,“Test #9”永远不会被回收(弱引用仍然存在),即使创建更多的对象并尝试第二次。
顺便说一下:问这个问题的主要原因是因为我在控制台中有一个\gctest
选项,用于在V8.Net和底层V8引擎之间测试垃圾收集。它在64位系统上可以运行,但不支持32位。