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

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

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.hqwc.cn/news/219466.html

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

相关文章

13年老鸟总结,性能测试方法汇总+性能响应很慢排查方法(详全)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、性能测试包含哪…

JsonRPC协议详解(协议介绍、请求示例、响应示例)

JsonRPC协议详解 什么是RPC&#xff1f; RPC&#xff08;远程过程调用&#xff09;是一种用于实现分布式系统中不同进程或不同计算机之间通信的技术。它允许我们像调用本地函数一样调用远程计算机上的函数&#xff0c;使得分布式系统的开发变得更加简单和高效。 什么是JsonRP…

<JavaEE> Java中线程有多少种状态(State)?状态之间的关系有什么关系?

目录 一、系统内核中的线程状态 二、Java中的线程状态 一、系统内核中的线程状态 状态说明就绪状态线程已经准备就绪&#xff0c;随时可以接受CPU的调度。阻塞状态线程处于阻塞等待&#xff0c;暂时无法在CPU中执行。 二、Java中的线程状态 相比于系统内核&#xff0c;Java…

【开源】基于Vue+SpringBoot的食品生产管理系统

项目编号&#xff1a; S 044 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S044&#xff0c;文末获取源码。} 项目编号&#xff1a;S044&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 加工厂管理模块2.2 客户管理模块2.3…

基于springboot实现学生成绩管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现学生成绩管理系统演示 摘要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&am…

【Linux篇】gdb调试器的使用

gdb调试器之常用指令 前言一 . 程序的两种发布模式二 . gdb调试器的使用1> 调用调试器进入调试环境2 > 退出调试3 > gdb中常用调试指令 前言 gdb作为Linux下一款好用且强队的调试工具&#xff0c; 支持对 C C go Java 等多种高级编程语言进行调试.对于在Linux下进行编…

YOLOv5轻量化改进之MobileNetv3

目录 一、原理 二、代码 三、应用到YOLOv5 一、原理 我们提出了基于互补搜索技术和新颖架构设计相结合的下一代mobilenet。MobileNetV3通过硬件网络架构搜索(NAS)和NetAdapt算法的结合来调整到移动电话cpu,然后通过新的架构进步进行改进。本文开始探索自动搜索算法和网络设计…

烧烤店点餐外卖配送管理小程序作用如何

烧烤是人们爱吃的食品之一&#xff0c;尤其到了晚上商业小吃街&#xff0c;烧烤店里往往是坐满了人&#xff0c;甚至还有排队的&#xff0c;从业商家众多&#xff0c;足可见该餐饮细分领域在市场中的欢迎程度。 而在实际经营中&#xff0c;烧烤店经营痛点也不小。 随着互联网…

线性分组码的奇偶校验矩阵均匀性分析

回顾信道编解码知识&#xff0c;我们知道信道编码要求编码具有检纠错能力&#xff0c;作为FEC&#xff08;forward error correction&#xff09;前向纠错编码的一类&#xff0c;线性分组码表示校验位与信息位的关系能够线性表示。 在这篇文章中&#xff0c;并不是要讨论信道编…

vue3+ts 兄弟组件之间传值

父级&#xff1a; <template><div><!-- <A on-click"getFlag"></A><B :flag"Flag"></B> --><A></A><B></B></div> </template><script setup lang"ts"> i…

vivado产生报告阅读分析23-时序路径特性报告

时序路径特性报告 下图显示了在“ Timing Mode ” &#xff08; 时序模式 &#xff09; 下运行“ Report Design Analysis ” &#xff08; 设计分析报告 &#xff09; 的输出示例 &#xff0c; 其中显示了设计中 10 条最差建立路径的路径特性。在 Vivado IDE 中选中“ Repo…

飞翔的鸟小游戏

第一步是创建项目 项目名自拟 第二步创建个包名 来规范class 再创建一个包 来存储照片 如下&#xff1a; package game; import java.awt.*; import javax.swing.*; import javax.imageio.ImageIO;public class Bird {Image image;int x,y;int width,height;int size;doub…