gpt4 book ai didi

c# - 32 位和 64 位应用程序之间的 GC 行为不一致

转载 作者:太空狗 更新时间:2023-10-29 17:57:10 26 4
gpt4 key购买 nike

在使用 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 位模式下调试某些东西,但没有调用终结器(至少,不是强制调用)。对象只是坐在那里,永远不会被收集(我可以看到所有弱引用仍然具有值(value))。在 64 位模式下,所有弱引用都按预期清除,并调用所有终结器。

注意:虽然上面的代码规模很小,但我注意到在 32 位模式下,许多 更多 对象卡在 GC 中,直到稍后创建更多对象(即使在“收集”时)并调用“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 位。在我的系统上,即使在创建更多对象并尝试第二次之后,“测试 #9”也永远不会被收集(弱引用仍然存在)。

仅供引用:问这个问题的主要原因是因为我的控制台中有一个 \gctest 选项,用于测试 V8.Net 和 native 端的底层 V8 引擎之间的垃圾收集。它适用于 64 位,但不适用于 32 位。

最佳答案

在 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 所注意到的),周围可能存在变量的“幽灵”副本,它们的生命周期延长到方法结束(当您在 Debug模式下编译代码时,或者您有一个附加调试器(F5 而不是 Ctrl+F5),变量的生命周期延长到方法结束以简化调试)

例如,对象初始化(当您执行类似 new Foo { I = 5 } 的操作时)会创建一个隐藏的局部变量。

关于c# - 32 位和 64 位应用程序之间的 GC 行为不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30254539/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com