的run代码_小心使用 Task.Run 续篇

关于前两天发布的文章:为什么要小心使用 Task.Run,对文中演示的示例到底会不会导致内存泄露,给很多人带来了疑惑。这点我必须向大家道歉,是我对导致内存泄漏的原因没描述和解释清楚,也没用实际的示例证实,是我的错。

但是,文中示例演示的 Task.Run 捕获类成员的情况,确实会有内存泄漏的风险,我将在本文演示给大家看。

如果一个对象(或数据)不需要再使用了,但依然还一直占据内存空间,则视为内存泄漏。这一点大家观点是一致的吧,那如何来检测对象有没有被回收呢?

我们知道,在 C# 中,实例对象被释放回收,必然会执行析构函数。所以我们可以对一个类重写其析构函数,如果该类的实例对象使用完后,强制执行 GC 回收,其析构函数依然不被执行,则说明 GC 没有回收该对象。若 GC 后面一直不回收这个对象,则说明存在内存泄漏。

手动强制执行 GC 回收的代码如下:

GC.Collect();GC.WaitForPendingFinalizers();GC.Collect();

这三句代码可以确保 GC 把所有能搜索到的可回收对象清理干净。注意:不推荐在生产环境这样写。

我们还是用 为什么要小心使用 Task.Run 这篇文章用到的示例,只是为了测试稍加修改了一下:

class Program{    static void Main(string[] args)    {        Test();        // 对不需要再使用的资源强制回收        GC.Collect();        GC.WaitForPendingFinalizers();        GC.Collect();        // 程序保活        while (true)        {            Thread.Sleep(100);        }    }    static void Test()    {        var myClass = new MyClass();        myClass.Foo();        // 到这,myClass对象不需要再使用了    }}public class MyClass{    private int _id;    private List _list;    public Task Foo()    {        return Task.Run(() =>        {            Console.WriteLine($"Task.Run is executing with ID {_id}");            Thread.Sleep(100); // 模板耗时操作        });    }    ~MyClass()    {        Console.WriteLine("MyClass instance has been colleted.");    }}

我们在 myClass 对象使用完后,手动强制执行 GC 回收,运行结果如下:

2c9b4824c8637efe1f35e417bc702860.png

我们看到 MyClass 的析构函数一直没有执行,也就意味着它的实例一直没有被回收。

现在我们修改 MyClass 类的 Foo 方法,改用本地(局部)变量试一试:

...public Task Foo(){    var localId = _id;    return Task.Run(() =>    {        Console.WriteLine($"Task.Run is executing with ID {localId}");    });}...

再运行看看效果:

a79ec003c7d028922cadfa16d87eb7ef.png

这次我们可以看到,MyClass 的析构函数执行了,说明实例对象被回收了。

前后唯一区别是,前者在 Task.Run 的匿名方法中捕获了类的成员,而后者使用了本地变量。前者出现了内存泄漏,后者避免了内存泄漏。

所以,在 Task.Run 的匿名方法中捕获类的成员,确实有可能导致内存泄漏(注意是有可能而不是一定)。

那背后的原因是什么呢?我在上一篇文章是这样解释的:

私有成员 _id 被 Task.Run 的匿名方法捕获使用,进而导致 MyClass 实例被引用。当外部使用完 MyClass 实例时,本该由 GC 回收的时候却发现它还被其它资源引用着,所以 GC 认为该实例不应该被回收,也就可能永远失去了被回收的机会。

这个解释有很大的问题,至少给广大读者带来了两大疑惑:

  1. 由于值类型是拷贝的方式赋值,所以捕获的本地变量和类成员指向的是各自的值,对本地变量的捕获不会影响到整个类。但如果把 _id 改为引用类型(如 String),那两者指向的就是同一个对象值,那是不是意味着即便使用本地变量也还是无法避免内存泄漏的问题?
  2. GC 第一次回收时发现 myClass 实例存在被捕获的成员,则认为它不应该被回收。那当 Task.Run 执行完后, 被捕获的成员也使用完了,GC 再次搜索时不就可以回收 myClass 对象吗?只是晚了一些时间回收而已嘛。

感谢善于思考提出疑惑的读者们,为你们点赞。

这两大疑惑该如何解释?后半部分我还没写完,大家可以先思考一下,我将在下一篇给大家解惑,望大家见谅。当然,我的解释也不一定会是对的,希望大家带着怀疑的态度和批判性思维来看我的文章,也请大家分享自己的理解和观点。

-

精致码农

带你洞悉编程与架构

点头像关注,不错过网海相遇的缘分[比心]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/561645.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Java+Spring+vue+element实现旅游信息管理平台系统

博主介绍:✌公司项目主程、全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,CSDN博客之星TOP100、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业设计✌ 公众号:java奥斯卡 简历模板、学习资料、面试题库…

基于OneDNS实现上网安全防护和监控

前言介绍: 大家是不是经常遇到这种问题、明明上网页输入的是网址地址,打开的却是页游广告或者APP弹窗之类的。在上网的时候突然就打开一个“充值XX元就可获得流量大礼包”的页面。类似下面这样。 照成这样的原因是什么呢?网址输错了?有病毒木…

华为开启管理员模式_又一年的心动模式开启,华为nova8系列8号色撩人肺腑

年底一到,大家又要迎来一波换机热潮,来为自己的新年添一分新鲜感。身边很多小伙伴来找我推荐,当我问到他们的要求时,爱游戏的想要性能好的,经常在外的想要续航强的。喜欢拍照的想要拍照和拍视频好的,看重手…

基于Java生鲜蔬菜食品商城系统详细设计和实现

博主介绍:✌公司项目主程、全网粉丝10W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,CSDN博客之星TOP100、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业设计✌ 🍅文末获取源码联系🍅 🍅…

摄像头夜间拍摄画面有拖影_让客厅秒变健身房,OPPO智能电视R1+摄像头上手体验...

当前智能电视日趋普及,大屏电视资源也逐渐丰富,借助智能电视,消费者足不出户就能体验到更智能的人机交互和更便捷的生活服务。而购买OPPO智能电视R1所赠送的价值399元的摄像头,也赋予了OPPO智能电视R1更多的玩法,为我们…

【云原生】Spring Cloud是什么?Spring Cloud版本介绍

什么是SpringCloud 上一章节介绍了总体的SpringCloud的总体学习章节,因为最近项目刚好需要用到SpringCloud来搭建微服务项目、所以就跟着大家一起来再学习巩固下SpringCloud的相关知识 SpringCloud是基于SpringBoot提供了一套微服务解决方案,包括服务注…

sap 一代增强_在SAP故乡,感受“边缘智能”之变

汉诺威工业博览会SAP展台在德国,有奔驰、宝马等汽车巨头,但SAP仍然是德国市值最高的企业,目前这家企业正在发生什么变化?5G、人工智能、区块链、VR/AR、物联网等新技术如火如荼,正在港口、汽车、叉车制造等客户带什么样…

基于Java+SpringBoot+vue+element实现餐厅点餐系统平台

博主介绍:✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,CSDN博客之星TOP100、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业设计✌ 🍅文末获取源码联系🍅 精彩专栏推荐👇&a…

字典添加数据_MATLAB自动化——EXCEL与数据字典管理(一)

以下平台同步更新,欢迎喜欢的朋友收藏、分享知乎专栏:汽车电控杂谈微信公众号:AutoGeeker在从EXCEL自动生成Signal和Parameter到Workspace中一文中,我们将所有设计数据都定义在基础工作区。将设计数据存储位置设置在基础工作区&am…

【云原生】微服务架构SpringCloud和Dubbo的区别?

现在做技术开发都在转型微服务化架构、目前主要的选择就是Dubbo和SpringCloud、 Dubbo dubbo启动流程图 先说说Dubbo吧!Dubbo是基于Tcp协议、是阿里巴巴开源的分布式服务治理框架,出现的时间比Spring Cloud早,并且当时国内在这方面并未成熟&…

ddmmyy日期格式是多少_解锁9个日期时间计算套路,效率提高3.2%

小伙伴们好啊,今天老祝和大家学习一组日期时间计算的套路,让工作效率再高一点点。1、日期时间合并如下图,需要将A列日期和B列的时间合并到一起,变成既有日期又带有时间的数据。C2公式为:A2B22、日期时间拆分如下图&…

基于Java+SpringBoot+vue+element实现婚纱摄影网系统

博主介绍:✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,CSDN博客之星TOP100、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业设计✌ 🍅文末获取源码联系🍅 精彩专栏推荐👇&a…

【云原生】SpringCloud-Spring Boot Starter使用测试

目录 Spring Boot Starter是什么? 以前传统的做法 使用 Spring Boot Starter 之后 starter 的理念: starter 的实现: 创建Spring Boot Starter步骤 在idea新建一个starter项目、直接执行下一步即可生成项目。 在xml中加入如下配置文件&…

otn系统中常用的电层_自动化系统中常用的液位计

1、磁致伸缩液位计磁致伸缩液位计由探测杆、电路单元和浮子组成。首先,由电路单元提供电流脉冲,接着脉冲按照磁致伸缩线向下方向传输,构成环形磁场。浮子将会沿着探测杆并随液位的变化而往复移动。同时,浮子内的永磁铁产生一个磁场…

【云原生】微服务SpringCloud-eureka(server)集群搭建

目录 工作原理: eureka 高可用集群 项目创建: Maven 依赖 本地hosts文件修改 启动服务测试 工作原理: Spring Cloud框架下的服务发现Eureka包含两个组件 分别是: Eureka Server与Eureka Client Eureka Server,也称为服务注册中心。各个…

log解析工具 px4_console.log(console.log) = ?

在开始今天的内容之前,先想一下 console.log(console.log) 的结果是啥。前面有一篇文章 别担心把 console 带到线上 介绍了关于 console 在线上不打印的操作,今天我给大家普及另外一种技巧:通过 url 参数控制。比如线上访问地址是&#xff1a…

基于Java+SpringBoot+vue实现图书借阅和销售商城一体化系统

博主介绍:✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,CSDN博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业设计✌ 🍅文末获取源码联系🍅 精彩专栏推荐👇&#x1…

【云原生】开源数据分析 SPL 轻松应对 T+0

T0问题 T0查询是指实时数据查询,数据查询统计时将涉及到最新产生的数据。在数据量不大时,T0很容易完成,直接基于生产数据库查询就可以了。但是,当数据量积累到一定程度时,在生产库中进行大数据量的查询会消耗过多的数…

这款国产API神器工具也太强了吧...让我放弃了postman

今天我发现了一款国产化的API工具,去官网看了下它的中文页面,觉得很干净、倍感亲切,我感觉Eolink结合了postman 和 swagger 的优点。摒弃了不足、甚至发生了公开踩踏事件,最近国产API管理工具越来越卷,但最后还是要回归…

快收藏!最适合计算机大学生的Java毕业设计项目--音乐视频网站系统!

博主介绍:✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,CSDN博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业设计✌ 🍅文末获取源码联系🍅 精彩专栏推荐👇&#x1…