我注意到使用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位模式下的许多 More 对象粘在GC中,直到以后创建更多对象(即使"收集"时,和" Waitforpending -Finalizers"被称为)。在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位中不起作用。在我的系统上,"测试#9"永远不会收集(即使创建更多对象并尝试第二次,也没有收集薄弱的参考)。
fyi:提出问题的主要原因是因为我的控制台中有一个gctest
选项,可以在天然侧的V8.NET和基础V8引擎之间测试垃圾收集。它起作用的64位,但不工作32。
x86和x64上的VS2013 .net 4.5 no repro:
class Program
{
class Test
{
public readonly int I;
public Test(int i)
{
I = i;
}
~Test()
{
Console.WriteLine("Finalizer for " + I);
}
}
static void Tester()
{
var t = new Test(1);
}
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);
var t = new Test(2);
t = null;
new Test(3);
Tester();
Console.WriteLine("Pre GC");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Post GC");
Console.ReadKey();
}
}
请注意,(如@sriram Sakthivel所注意到的),可能会有您的变量的"幽灵"副本,它们的寿命延长到方法结束(当您以调试模式编译代码或您有一个时,附加的调试器(F5而不是Ctrl F5),变量的寿命已延长,直到方法结束以减轻调试)
例如,对象初始化(当您执行类似New Foo {i = 5})的事情会创建一个隐藏的本地变量。