当前位置: 首页 > news >正文

.NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)

垃圾回收机制有一些未定义部分,一般来说不要依赖于这些未定义部分编程,否则容易出现一些诡异的 bug 或者不稳定的现象。

本文介绍局部变量这部分的细节,而这点在 .NET Framework 和 .NET Core 默认情况下的表现有差别。


本文内容

    • 问题代码
    • 原因

问题代码

看看下面这段代码,你觉得会输出 Foo is collected 吗?

class Program
{
    static void Main(string[] args)
    {
        new WeakReference<Foo>(new Foo());
        GCTest();
    }

    private static void GCTest()
    {
        while (true)
        {
            Thread.Sleep(500);
            GC.Collect();
        }
    }
}

public class Foo
{
    ~Foo()
    {
        Console.WriteLine("Foo is collected");
    }
}

如果你没有修改默认的编译设置,那么答案应该是:

  • 全部 .NET Framework 下都输出 Foo is collected
  • .NET Core 2.x 及以下输出 Foo is collected
  • .NET Core 3.x 及以上不会有任何输出

额外的,.NET Core 2.1 - .NET Core 3.x 通过设置可以改变此行为,本文文末会说。

然而所有这些平台编译后的 IL 都差不多。虽然引用的程序集不一样,但代码都是一样的。所以问题不在编译器,而在运行时。

.method private hidebysig static 
    void Main (
        string[] args
    ) cil managed 
{
    // Header Size: 1 byte
    // Code Size: 17 (0x11) bytes
    .maxstack 8
    .entrypoint

    /* (12,13)-(12,45) Program.cs */
    /* 0x00000251 7305000006   */ IL_0000: newobj    instance void Walterlv.Demo.Weak.Foo::.ctor()
    /* 0x00000256 730C00000A   */ IL_0005: newobj    instance void class [System.Runtime]System.WeakReference`1<class Walterlv.Demo.Weak.Foo>::.ctor(!0)
    /* 0x0000025B 26           */ IL_000A: pop
    /* (14,13)-(14,22) Program.cs */
    /* 0x0000025C 2802000006   */ IL_000B: call      void Walterlv.Demo.Weak.Program::GCTest()
    /* (15,9)-(15,10) Program.cs */
    /* 0x00000261 2A           */ IL_0010: ret
} // end of method Program::Main

这个问题我提在了 GitHub 上,大家可以去看看:

  • GC.Collect: Object without reference will be collected in .NET Framework but will NOT been collected in .NET Core · Issue #36265 · dotnet/runtime

原因

当然,当变量脱离作用域后 GC 本应回收,但在同一个函数中定义的变量是否脱离作用域却是未定义的。你可以经常在 DEBUG 下发现依然可访问的变量,但在 RELEASE 下无法访问变量就体现了这种未定义带来的行为差异。

.NET Core 3.0 开始引入了分层编译(Tiered Compilation)。在开启了分层编译的情况下,JIT 执行方法时先会快速编译,随后如果此方法访问频繁会在后台优化这个编译然后替换掉之前编译的方法,以提升后续的运行性能。

在分层编译被启用的情况下,GC 的行为有改变,局部变量不再及时回收。当然以后有更优化的分层编译后,可能有新的行为改变。

如果要关闭分层编译,可以在项目文件中设置 TieredCompilationfalse,也可以设置环境变量 COMPlus_TieredCompilation=0。这两个是等价的。

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
+   <TieredCompilation>false</TieredCompilation>
  </PropertyGroup>

关于分层编译,可以阅读林德熙的博客:

  • dotnet core 2.1 使用分层编译

本文一开始说的行为改变,指的就是开关分层编译。.NET Core 2.1 开始支持分层编译但默认关闭,而 .NET Core 3.0 开始默认开启。所以在支持的框架上你可以开启或关闭。


参考资料

  • Compilation config settings - .NET Core - Microsoft Docs

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • git 乱改你的换行符?一句话设置让 git 不再碰你某个文件的换行符
  • Linux Shell 中需要转义的字符
  • Unity3D 入门:Unity Editor 编辑器常用快捷键
  • Unity3D 入门:Unity 项目版本管理建议使用的 .gitignore 忽略文件和 .gitattributes 文件(2020年4月更新)
  • Unity3D 入门:让 C# 脚本公开可在 Unity 编辑器中设置的属性
  • Unity3D 入门:如何管理 Unity 项目中的 NuGet 包?使用第三方 NuGet 包管理器——NuGetForUnity
  • Unity3D 入门:如何在脚本中找到游戏对象的父子级 祖孙级对象和它们的组件
  • Unity3D 入门:如何制作天空效果?天空盒的使用
  • Unity3D 入门:使用 Visual Studio 开发 Unity C# 脚本,说说根目录的那些 sln 和 csproj 文件
  • Unity3D 入门:最简单的控制视角,以及控制角色前进、转向的脚本
  • 比较 Windows 上四种不同的文件(夹)链接方式(NTFS 的硬链接、目录联接、符号链接,和大家熟知的快捷方式)
  • 了解 Windows Linux 下命令行 Shell 启动程序传参的区别,这下不用再担心 Windows 下启动程序传参到 Linux 下挂掉了
  • 适合 .NET 开发者用的 GitHub Actions(时不时更新)
  • 《Java编程思想》读书笔记-对象导论
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • 3.7、@ResponseBody 和 @RestController
  • Linux快速复制或删除大量小文件
  • MySQL主从复制读写分离及奇怪的问题
  • nodejs调试方法
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • VUE es6技巧写法(持续更新中~~~)
  • Vultr 教程目录
  • webpack入门学习手记(二)
  • 看域名解析域名安全对SEO的影响
  • 利用jquery编写加法运算验证码
  • 前端临床手札——文件上传
  • 前端自动化解决方案
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 网页视频流m3u8/ts视频下载
  • 一文看透浏览器架构
  • ​马来语翻译中文去哪比较好?
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #stm32驱动外设模块总结w5500模块
  • #WEB前端(HTML属性)
  • (MATLAB)第五章-矩阵运算
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (四) Graphivz 颜色选择
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (译) 函数式 JS #1:简介
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (转) Android中ViewStub组件使用
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • (转载)Linux网络编程入门
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .bat批处理(二):%0 %1——给批处理脚本传递参数
  • .gitignore文件_Git:.gitignore
  • .net framework profiles /.net framework 配置
  • .Net IOC框架入门之一 Unity
  • .net 反编译_.net反编译的相关问题
  • .NET 设计模式—适配器模式(Adapter Pattern)