首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >32位和64位应用程序之间的GC行为不一致

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

Stack Overflow用户
提问于 2015-05-15 08:05:41
回答 1查看 504关注 0票数 9

我注意到在使用VS 2013在.Net 4.0中编译32位和64位的控制台应用程序时,GC的行为不一致。

考虑以下代码:

代码语言:javascript
复制
class Test
{
    public static bool finalized = false;
    ~Test()
    {
        finalized = true;
    }
}

Main() ..。

代码语言:javascript
复制
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更好。只是想弄明白为什么。

编辑:这里有更好的代码来显示不同之处:

代码语言:javascript
复制
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位。

EN

回答 1

Stack Overflow用户

发布于 2015-05-15 08:47:11

在VS2013 + .NET 4.5上不复制x86和x64:

代码语言:javascript
复制
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}的操作时)将创建一个隐藏的局部变量。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30254539

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档