我注意到在使用VS 2013在.Net 4.0中编译32位和64位的控制台应用程序时,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位模式下,有更多的对象卡在GC中,直到稍后创建更多的对象(即使调用了"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“永远不会被收集(弱引用仍然存在),即使在创建了更多的对象并第二次尝试之后。
FYI:问这个问题的主要原因是我的控制台中有一个\gctest选项来测试V8.Net和本地底层V8引擎之间的垃圾收集。它工作在64位,但不是32位。
发布于 2015-05-15 08:47:11
在VS2013 + .NET 4.5上不复制x86和x64:
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)时,变量的生存期将延长到方法的结束,以方便调试)。
例如,对象初始化(当您执行类似于新Foo {i=5}的操作时)将创建一个隐藏的局部变量。
https://stackoverflow.com/questions/30254539
复制相似问题