C#学习(十四)——垃圾回收、析构与IDisposable

一、何为GC

数据是存储在内存中的,而内存又分为Stack栈内存和Heap堆内存

Stack栈内存Heap堆内存
速度快、效率高结构复杂
类型、大小有限制对象
只能保存简单的数据引用数据类型
基础数据类型、值类型-

举个例子

var c= new Customer{id: 123,name: "Jack"address: "珠海"
}

在堆内存中就保存了信息

#1000
123Jack珠海

而在栈内存中仅保存了需要调用的地址c* = 1000——reference
当删除时,需要先删除堆内存的数据,再删除栈内存的数据,然而如果先删除了栈内存的数据,那么对内存中的数据就再也无法找到,也无法删除,无法重复利用,就会造成内存泄漏。
因此,为了便捷,如JAVA、C#等语言引入了垃圾回收机制,使得程序员只需要关注于对象本身即可。

如果一段对象的引用数量为0,则代表对象的声明周期结束。

二、GC是如何工作的

运行垃圾回收的成本很高,需要不断地遍历所有数据,因此使用了复杂的机制来解决高效运行问题。——Generations分代回收
将数据对象分成三组

G0G1G2
暂时性的对象中长期对象长期对象
每次运行GC都检查检查频率下降GC偶尔来检查

内存不足时,GC会强行清理所有对象

GC不止处理垃圾清理

  • [ 标记、清理堆内存中的死掉的对象]
  • [ 压缩内存、消除间隙,提高对象的创建、读取效率 ]
    不过GC不会处理过大的内存区块

GC独立线程

  • [ GC跑在独立的后台线程中 ]
  • [ 每次运行都需要付出代价,需要消耗计算资源 ]
  • [ 尽可能的减少运行频率、并且尽可能提高运行效率 ]

三、析构方法and终结器

终结器(以前称为析构函数)用于在垃圾回收器收集类实例时执行任何必要的最终清理操作。在大多数情况下,通过使用System.Runtime.InteropServices.SafeHandle或派生类包装任何非托管句柄,可以免去编写终结器的过程。

若无必要,不要使用
使用终结器会造成性能的损失。

代码举例

public class AnywayClass
{public AnywayClass(){Console.WriteLine("AnywayClass类创建");}~AnywayClass(){Console.WriteLine("AnywayClass类销毁");}
}
class Program
{static void Main(string[] args){var anyway = new AnywayClass();Console.WriteLine("程序结束");}
}

但是运行后会发现,程序并不会输出“AnywayClass类销毁”,要判断当前实例是否还会被引用,是根据语句的区域决定的,也就是说,它的作用域是整个main方法,因此垃圾回收是在整个main方法外面,因此看不到析构方法的输出。

因此要看到输出,就要降低对象的作用域。

public class AnywayClass
{public AnywayClass(){Console.WriteLine("AnywayClass类创建");}~AnywayClass(){Console.WriteLine("AnywayClass类销毁");}
}public class SecondClass : AnywayClass
{public SecondClass(){Console.WriteLine("SecondClass创建");}~SecondClass(){Console.WriteLine("SecondClass销毁");}
}public class ThirdClass : SecondClass
{public ThirdClass(){Console.WriteLine("ThirdClass创建");}~ThirdClass(){Console.WriteLine("ThirdClass销毁");}
}
class Program
{static void DoSomething(){new ThirdClass();}static void Main(string[] args){DoSomething();GC.Collect();//进行垃圾回收GC.WaitForPendingFinalizers();//等待所有需要被回收的对象全部被回收Console.WriteLine("程序结束");}
}

  • [ 一个类只能有一个终结器 ]
  • [ 不能继承或重载终结器 ]
  • [ 不能手动调用终结器,只能由垃圾回收器自动调用 ]
  • [ 终结器不使用修饰符或参数 ]

四、Disposable模式

GC不是万能的,GC只能处理托管资源(即那些使用new关键字创建的对象),而无法处理外部资源(比如文件的读取、数据库请求、网络访问等)。
文件读取、网络访问、数据库请求无法托管在.Net平台内部,如果不清理外部资源,将会极大的占用电脑资源,内存不断增长,最后崩溃退出。
因此使用IDisposable实现资源的释放

namespace System
{//释放外部资源public interface IDisposable{void Disposable();}
}

典型案例

public class Custom : Disposable
{void Method();void Dispose();
}static main()
{using (var obj = new Customs()){obj.Method();}
}

使用Dispose方法就必须使用using关键字

五、使用IDisposable回收非托管资源

首先在nuget工具中下载安装SqlClient
SqlClient
示例代码
Program.cs

class Program
{static void Main(string[] args){for(int i = 0; i < 1000; i++){var db = new DatabaseHelper();var date = db.GetData();db.Close();Console.WriteLine($"[{DateTime.Now.ToLongTimeString()}; {date}]");}Console.WriteLine("程序结束");}
}

DatabaseHelper.cs

public class DatabaseHelper
{private SqlConnection _connection;private string _connectionString = $"数据库连接字符串;" +$"App = Recycle;" +$"Max Pool Size = 100;" +$"Pooling = true;";public string GetData(){if(_connection == null){_connection = new SqlConnection(_connectionString);_connection.Open();Console.WriteLine("数据库连接已开启");}var command = _connection.CreateCommand();command.CommandText = "select getdate();";return command.ExecuteScalar().ToString();//完成最后输出}public void Close(){Console.WriteLine("数据库连接已关闭");_connection.Close();_connection.Dispose();//注销数据库的连接对象_connection = null;}
}

实际上,程序员忘记关闭数据库外部资源是一个十分常见的低级错误,为了避免此类错误,可以使用IDisposable接口
Program.cs

class Program
{static void Main(string[] args){for(int i = 0; i < 1000; i++){using (var db = new DatabaseHelper()){var date = db.GetData();Console.WriteLine($"[{DateTime.Now.ToLongTimeString()}; {date}]");};                }Console.WriteLine("程序结束");}
}

DatabaseHelper.cs

public class DatabaseHelper : IDisposable
{private SqlConnection _connection;private string _connectionString = $"Data Source=localhost\\SQLEXPRESS;Initial Catalog=master;Integrated Security=True;Encrypt=True;Trust Server Certificate=True;" +$"App = Recycle;" +$"Max Pool Size = 100;" +$"Pooling = true;";public string GetData(){if(_connection == null){_connection = new SqlConnection(_connectionString);_connection.Open();Console.WriteLine("数据库连接已开启");}var command = _connection.CreateCommand();command.CommandText = "select getdate();";return command.ExecuteScalar().ToString();//完成最后输出}private bool disposedValue;protected virtual void Dispose(bool disposing){if (!disposedValue){if (disposing){// TODO: 释放托管状态(托管对象)Console.WriteLine("数据库连接已关闭");_connection.Close();_connection.Dispose();//注销数据库的连接对象_connection = null;}// TODO: 释放未托管的资源(未托管的对象)并重写终结器// TODO: 将大型字段设置为 nulldisposedValue = true;}}// // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器// ~DatabaseHelper()// {//     // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中//     Dispose(disposing: false);// }public void Dispose(){// 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中Dispose(disposing: true);GC.SuppressFinalize(this);}
}

注:

  • [ Dispose可以用来回收如数据库连接、文件读取、HTTP长连接等无法托管在.net平台中的外部资源 ]
  • [ 使用Dispose必须实现IDisposable接口 ]
  • [ IDisposable接口需要配合using关键词才能完成生命周期的托管 ]

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

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

相关文章

Java中String类有哪些常用方法?

Java中的String类提供了许多有用的方法&#xff0c;用于处理字符串。以下是一些常用的方法及其简要描述&#xff1a; 1. **charAt(int index)**&#xff1a;返回指定位置的字符。 2. **length()**&#xff1a;返回字符串的长度。 3. **substring(int beginIndex, int endInd…

微信小程序手势冲突?不存在的!

原生的应用经常会有页面嵌套列表&#xff0c;滚动列表能够改变列表大小&#xff0c;然后还能支持列表内下拉刷新等功能。看了很多的小程序好像都没有这个功能&#xff0c;难道这个算是原生独享的吗&#xff0c;难道是由于手势冲突无法实现吗&#xff0c;冷静的思考了一下&#…

Google验证码,扫描绑定,SpringBoot+ vue

文章目录 后端1.使用Google工具类这个 类的 verifyTest 方法可以判断扫描绑定之后的app上面验证码的准确性。这个类通过g_user,g_code(就是谷歌验证器的secret,这个你已经插入到数据库 中)来生成相关二维码。2.用工具类自带的g_user,g_code来生成二维码2.1通过请求来生成相关二…

你知道vector底层是如何实现的吗?

你知道vector底层是如何实现的吗&#xff1f; vector底层使用动态数组来存储元素对象&#xff0c;同时使用size和capacity记录当前元素的数量和当前动态数组的容量。如果持续的push_back(emplace_back)元素&#xff0c;当size大于capacity时&#xff0c;需要开辟一块更大的动态…

【InternLM 实战营笔记】XTuner 大模型单卡低成本微调实战

XTuner概述 一个大语言模型微调工具箱。由 MMRazor 和 MMDeploy 联合开发。 支持的开源LLM (2023.11.01) InternLM Llama&#xff0c;Llama2 ChatGLM2&#xff0c;ChatGLM3 Qwen Baichuan&#xff0c;Baichuan2 Zephyr 特色 傻瓜化&#xff1a; 以 配置文件 的形式封装了大…

WebGIS----wenpack

学习资料&#xff1a;https://webpack.js.org/concepts/ 简介&#xff1a; Webpack 是一个现代化的 JavaScript 应用程序的模块打包工具。它能够将多个 JavaScript 文件和它们的依赖打包成一个单独的文件&#xff0c;以供在网页中使用。 Webpack 还具有编译和转换其他类型文…

自学新标日第六课(单词部分 未完结)

第六课 单词 单词假名声调词义来月らいげつ1下个月先月せんげつ1上个月夜中よなか3午夜昨夜ゆうべ0昨天晚上コンサートこんさーと1音乐会クリスマスくりすます3圣诞季誕生日たんじょうび&#xff13;生日こどもの日こどものひ&#xff15;儿童节夏休みなつやすみ&#xff13;…

看待事物的层与次 | DBA与架构的一次对话交流

前言 在计算机软件业生涯中,想必行内人或多或少都能感受到系统架构设计与数据库系统工程的重要性,也能够清晰地认识到在计算机软件行业中技术工程师这个职业所需要的专业素养和必备技能! 背景 通过自研的数据库监控管理工具,发现 SQL Server 数据库连接数在1-2K之间,想…

Yii2中如何使用scenario场景,使rules按不同运用进行字段验证

Yii2中如何使用scenario场景&#xff0c;使rules按不同运用进行字段验证 当创建news新闻form表单时&#xff1a; 添加新闻的时候执行create动作。 必填字段&#xff1a;title-标题&#xff0c;picture-图片&#xff0c;description-描述。 这时候在model里News.php下rules规则…

星座每日运势 api接口

接口数据api 接口平台&#xff1a;https://api.yuanfenju.com/ 开发文档&#xff1a;https://doc.yuanfenju.com/zhanbu/yunshi.html 支持格式&#xff1a;JSON 请求方式&#xff1a;HTTP POST <?php//您的密钥 $api_secret "wD******XhOUW******pvr"; //请…

利用coze 搭建“全功能“微信客服(2)

紧跟上篇 利用coze 搭建"全功能"微信客服&#xff08;1&#xff09;&#xff0c;不知道来龙去脉自行查阅 先表扬下coze: coze 是国内少数开放平台之一&#xff0c;里面提供各种插件还可以开发工作流&#xff0c;让你可以实现多模态全功能大模型 吐槽 没有API开放接口…

国外最流行的是AI,国内最流行的是AI培训教程

国外最流行的是AI&#xff0c;国内最流行的是AI培训教程。 最近李一舟AI教程事件&#xff0c;验证了这句话。 如今给客户做方案项目里能加点AI色彩&#xff0c;立项的成功率都变大(特别是事业单位)。 正因如此&#xff0c;大家都在狂补AI的知识&#xff0c;不然肚子里没点墨水&…

2024亚马逊全球开店注册前需要准备什么?

在2023年出海四小龙SHEIN、Temu、速卖通AliExpress、TikTok Shop快速增长扩张&#xff0c;成为了中国跨境卖家“逃离亚马逊”的新选择。但是&#xff0c;跨境电商看亚马逊。当前&#xff0c;亚马逊仍然是跨境电商行业的绝对老大&#xff0c;占有将近70%成以上的业务份额。 作为…

threejs显示本地硬盘上的ply文件,通过webapi

由于ply文件是第三方提供的&#xff0c;threejs无法用绝路路径的方式显示ply 所以想通过webapi把ply通过url地址的方式给threejs 1.webapi部分 /// <summary>/// 获取PLY文件/// </summary>/// <returns></returns>[HttpPost(Name "GetPly&qu…

分享fastapi低级错误

我是创建表的时候把__tablename__ 写成__table__然后一直报这个错误

Android Activity跳转详解

在Android应用程序中&#xff0c;Activity之间的跳转是非常常见的操作&#xff0c;通过跳转可以实现不同界面之间的切换和交互。在本篇博客中&#xff0c;我们将介绍Android中Activity跳转的相关知识&#xff0c;包括基本跳转、传递参数、返回数据以及跳转到浏览器、拨号应用和…

端游如何防破解

在2023年这个游戏大年中&#xff0c;诸多热门大作涌现&#xff0c;作为世界级IP哈利哈利波特的衍生游戏——《霍格沃茨之遗》毫无悬念地成为2023年游戏圈的首款爆款作品&#xff0c;斩获了一众玩家的青睐。 在众多光环的加持下&#xff0c;《霍格沃茨之遗》很快被著名游戏破解…

【每日前端面经】2024-03-01

题目来源: 牛客 MVVM怎么实现 MVVM分别指View、Model、ViewModel&#xff0c;View通过View-Model的DOM监听器将事件绑定到Model上&#xff0c;而Model则通过Data Bindings来管理View中的数据&#xff0c;View-Model从中起到一个连接的作用 响应式: vue如何监听data的属性变化…

深入 Starknet 去中心化世界,探秘实用开发利器

Starknet 近期开放空投&#xff0c;面向 130 万地址总量发放超 7 亿枚 Token&#xff0c;让 ECMP 早期贡献者、GitHub 开源开发者、Starknet 用户等各个层面的生态参与者都得以深度参与。 盛宴的背后&#xff0c;是 Starknet 正迎来发展的关键机遇。在今年以太坊坎昆升级的背景…

从别人的开源项目学习并吸收经验,然后逐步搭建自己的Java项目是一个很好的学习方法

从别人的开源项目学习并吸收经验&#xff0c;然后逐步搭建自己的Java项目是一个很好的学习方法。以下是一些建议的步骤&#xff0c;帮助你从0开始搭建并不断完善自己的Java项目&#xff0c;直至达到高可靠、高稳定、高并发、高数据安全&#xff0c;并可以拆分为微服务的大型高质…