我注意到在使用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中,直到稍后创建更多对象(即使&#34 ;收集"和#34; 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位。在我的系统上,&#34;测试#9&#34;永远不会被收集(弱引用仍然存在),即使在创建了更多对象之后,又尝试了第二次。
仅供参考:提出这个问题的主要原因是因为我在我的控制台中有一个\gctest
选项来测试V8.Net与本机端底层V8引擎之间的垃圾收集。它工作在64位,但不是32。
答案 0 :(得分:3)
x86和x64上的VS2013 + .NET 4.5无重复:
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所注意到的),可能存在变量的“ghost”副本,它们的生命周期延长到方法结束时(在Debug模式下编译代码或者你有一个附加调试器(F5而不是Ctrl + F5),变量的生命周期一直延长到方法结束,以便于调试)
例如,对象初始化(当您执行类似new Foo {I = 5}的操作时)会创建一个隐藏的局部变量。