WeakReference 在 .Net Framework 和 .Net Core 之间的行为不同 [英] WeakReference behaves differently between .Net Framework and .Net Core

查看:26
本文介绍了WeakReference 在 .Net Framework 和 .Net Core 之间的行为不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

#nullable enable

namespace ConsoleApp1
{
    class Program
    {
        static void Main()
        {
            var list    = makeList();
            var weakRef = new WeakReference(list[0]);

            list[0] = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();

            Console.WriteLine(weakRef.IsAlive);
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        static List<int[]?> makeList()
        {
            return new List<int[]?> { new int[2] };
        }
    }
}

  • 无论是在 .Net Framework 4.8 上发布还是调试版本,代码打印 False.
  • 在 .Net 上发布或调试版本核心 3.1,该代码打印 True.
  • 是什么导致了这种行为差异?(这会导致我们的一些单元测试失败.)

    What is causing this difference in behaviour? (It's causing some of our unit tests to fail.)

    注意:我将列表初始化放入 makeList() 并关闭内联,试图使 .Net Core 版本与 .Net Framework 版本的工作方式相同,但无济于事.

    Note: I put the list initialisation into makeList() and turned off inlining in an attempt to make the .Net Core version work the same as the .Net Framework version, but to no avail.

    正如 Hans 指出的,添加一个循环可以修复它.

    As Hans pointed out, adding a loop fixes it.

    以下代码打印False:

    var list    = makeList();
    var weakRef = new WeakReference(list[0]);
    
    list[0] = null;
    
    for (int i = 0; i < 1; ++i)
        GC.Collect();
    
    Console.WriteLine(weakRef.IsAlive);
    

    但这会打印True:

    var list    = makeList();
    var weakRef = new WeakReference(list[0]);
    
    list[0] = null;
    
    GC.Collect();
    GC.Collect();
    GC.Collect();
    GC.Collect();
    
    // Doesn't seem to matter how many GC.Collect() calls you do.
    
    Console.WriteLine(weakRef.IsAlive);
    

    得到是某种奇怪的抖动...

    This has got to be some kind of weird Jitter thing...

    推荐答案

    仅仅因为某物允许被收集并不意味着它有义务被收集尽可能.虽然该语言声明允许 GC 确定永远不会再次读取局部变量,因此不会将其视为根,但这并不意味着您可以依赖正在收集的局部变量的内容上次阅读后立即.

    Just because something is allowed to be collected doesn't mean it's obligated to be collected as soon as is possible. While the language states that the GC is allowed to determine that a local variable is never read again, and thus not consider it a root, that doesn't mean you can rely on a local variable's contents being collected immediately after you last read from it.

    这不是运行时中定义的行为之间的一些变化,这是两个运行时中的未定义行为,因此它们之间的差异是完全可以接受的.

    This isn't some change between defined behavior in the runtime, this is undefined behavior in both runtimes, so differences between them is entirely acceptable.

    这篇关于WeakReference 在 .Net Framework 和 .Net Core 之间的行为不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆