Task.Run为什么会存在内存泄漏的风险?

news/2024/5/20 0:28:44 标签: java, 算法, c#, 开发语言, .netcore

由于值类型是拷贝方式的赋值,捕获的本地变量和类成员是指向各自的值,对本地变量的捕获不会影响到整个类。但如果把类中的值类型改为引用类型,那这两者最终指向的是同一个对象值,这是否意味着使用本地变量还是无法避免内存泄漏?

GC在第一次回收时,发现某实例还存在被捕获成员,则认为它不应该被回收。假如这个实例对象中存在Task.Run,当Task.Run执行完毕后,GC不就可以回收这个实例了吗?

public class TaskClass
    {
        private int _id;
        private List<string> _list;

        public Task Test()
        {
            var LocalID = _id;

            return Task.Run(() =>
            {
                Console.WriteLine("Task.Run is executing with ID={0}", LocalID);
                Thread.Sleep(1500);
            });
        }
    }

我们先把变量_id的值类型改为引用类型string,运行的结果是和int类型一致,这说明和值类型或引用类型无关。

我们知道,在创建引用类型时会在栈上开辟内存空间,在该地址存储该变量的名称,用于对地址的引用,该变量对应的值存储在托管堆中。局部变量Local ID和类成员_id,在栈中有不同的地址,栈中所指向到托管堆中的地址也是不同,但是托管堆地址中对应的值是相同的。

所谓被捕获就是被作用域捕获,当作用域结束时,该作用域内成员的地址空间也会被释放,至于地址指向的托管堆中的字符串,则不是作用域该关心的事情。当字符串值对应的地址空间没有变量指向时,就会被GC回收。

当CLR尝试搜索不再使用的对象时,它需要遍历托管堆上的对象。随着程序的不断运行,托管堆可能会不断变大,如果GC对整个托管堆回收,势必会造成对程序性能的影响,甚至崩贵。所以,为了优化这个过程,微软在CLR中使用了分带算法

分带算法就是把内存中的资源划分为三代,分别是Gen 0、Gen 1、Gen 2,GC遍历它们的频率由高到低。新创建对象的会被标记为Gen 0,GC扫描它们的频率最高;当GC进行一次扫描后,未被回收的对象会被标记为Gen 1;当GC扫描被标记为Gen 1的对象时,未被回收的对象被标记为Gen 2,Gen 2的回收被称为Full GC,只有在满足一定条件时才会执行。资源在内存中停留的时间越长,越不容易被回收。

在这里插入图片描述

当对象进入Gen 2时,没有一定的触发条件,资源是不会被回收的。

当我们理解分带算法后,上面那段代码相应的三个时间点:1、作用域的结束时间点;2、GC回收的时间点;3、Task.Run执行的结束点。

如果程序的执行顺序是1、3、2,那么就不会存在内存泄漏问题。但实际情况是,Task.Run一般是执行耗时操作,非耗时任务一般是不会使用Task.Run。所以程序执行的时间顺序可能是1、2、3,当GC回收该对象时,由于该对象的作用域还未被释放,GC会将该对象标记为Gen 1。如果Task.Run执行的时间够长,该对象会被标记为Gen 2,若没有相应的触发条件,该对象永远都不会被回收。

在大部分场景中,我们还是可以放心的去使用Task.Run。如果Task.Run中的局部变量捕获了类中的成员,使该对象进入Gen 2,Gen 2中未被释放的资源也是有限的,不可能是无限增加。当Gen 2中的资源累积到一定程度时,就会触发相应的条件,GC会将Gen 2中未被使用的资源释放。当然,我们还是要尽可能避免在Task.Run匿名类中捕获类成员。


http://www.niftyadmin.cn/n/5214096.html

相关文章

LeetCode.203移除链表元素(原链表操作、虚拟头结点)

LeetCode.203移除链表元素 1.问题描述2.解题思路3.代码 1.问题描述 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val …

count=0语句的位置

简洁一点的代码&#xff1a; 像count0这种语句要注意放好位置&#xff0c;尤其是在循环里。

[RK-Linux] recovery分区详解(二)

承接上一篇:[RK-Linux] recovery分区详解(一) 文章目录 四、SD 卡启动盘升级过程分析4.1 制作 SD 固件升级卡4.2 u-boot 执行4.3 recovery 执行五、恢复出厂设置四、SD 卡启动盘升级过程分析 4.1 制作 SD 固件升级卡 准备好 PC 机(windows 系统)、SD 卡、USB 读卡器。 SD…

Keil5个性化设置及常用快捷键

Keil5个性化设置及常用快捷键 1.概述 这篇文章是Keil工具介绍的第三篇文章&#xff0c;主要介绍下Keil5优化配置&#xff0c;以及工作中常用的快捷键提高开发效率。 第一篇&#xff1a;《安装嵌入式单片机开发环境Keil5MDK以及整合C51开发环境》https://blog.csdn.net/m0_380…

qt实现播放视屏的时候,加载外挂字幕(.srt文件解析)

之前用qt写了一个在windows下播放视频的软件&#xff0c;具体介绍参见qt编写的视频播放器&#xff0c;windows下使用&#xff0c;精致小巧_GreenHandBruce的博客-CSDN博客 后来发现有些视频没有内嵌字幕&#xff0c;需要外挂字幕&#xff0c;这时候&#xff0c;我就想着把加载…

免费不限字数的文本转语音AI配音工具,无需安装

上周给大家分享了AI绘本故事制作&#xff0c;很多小伙伴让我&#xff0c;推荐一款免费的AI配音&#xff0c;音色质量富有情感语调&#xff0c;而且手机上就能用的文本转语音工具。 OK&#xff0c;那么今天就给小伙伴们推荐一款我经常自用的AI配音工具&#xff0c;无需安装下载&…

ubuntu20.04配置OpenCV的C++环境

ubuntu20.04配置OpenCV的C环境 这里以opencv-3.4.16为例 复现https://github.com/raulmur/ORB_SLAM2此项目&#xff0c;需安装opencv及其他依赖&#xff0c;可见README.md详情 1.下载opencv源代码 https://opencv.org/releases/ 2.下载OpenCV的扩展包opencv_contrib&#x…

PTA-6-51(处理数组、字符串) 人口统计

题目&#xff1a; 本题运行时要求键盘输入10个人员的信息&#xff08;每一个人信息包括&#xff1a;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;民族&#xff09;&#xff0c;要求同学实现一个函数&#xff0c;统计民族是“汉族”的人数。 函数接口定义&#xff1a; pu…