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

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

相关文章

“环波罗的海”包围圈将正式形成

据“直新闻”的消息称&#xff0c;近日匈牙利国会同意了瑞典加入北约的申请&#xff0c;在走完相关后续程序后&#xff0c;瑞典就将成为北约第三十二个成员国&#xff0c;而北约对俄罗斯打造的“环波罗的海”包围圈也将正式形成&#xff0c;即除俄方外&#xff0c;波罗的海周边…

计算机网络之传输层 + 应用层

.1 UDP与TCP IP中的检验和只检验IP数据报的首部, 但UDP的检验和检验 伪首部 首部 数据TCP的交互单位是数据块, 但仍说TCP是面向字节流的, 因为TCP仅把应用层传下来的数据看成无结构的字节流, 根据当时的网络环境组装成大小不一的报文段.10秒内有1秒用于发送端发送数据, 信道…

Docker技术概论(3):Docker 中的基本概念

Docker技术概论&#xff08;3&#xff09; Docker 中的基本概念 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://…

详解字符串函数<string.h>(上)

1. strlen函数的使用和模拟实现 size_t strlen(const char* str); 1.1 函数功能以及用法 字符串长度 strlen函数的功能是计算字符串的长度。在使用时&#xff0c;要求用户传入需要计算长度的字符串的起始位置&#xff0c;并返回字符串的长度。 #include <stdio.h> #…

金融短信群发平台具有那些特点

金融短信群发平台的特点主要包括以下几个方面&#xff1a; 1.高效性&#xff1a;金融短信群发平台能够快速地发送大量的短信&#xff0c;使得金融信息能够迅速传达给目标客户&#xff0c;保证了信息的及时性和有效性。 2.安全性&#xff1a;金融短信群发平台对于信息的安全性非…

一文读懂ZKFair PFP-CyberArmy的参与价值与潜力

3月2日&#xff0c;ZKFair PFP-CyberArmy 将在 Element 上正式开始Public Sale。CyberArmy是遵循ERC-404协议所构建的战士形象NFT盲盒&#xff0c;总量9999个&#xff0c;每个盲盒对应一个战士形象&#xff0c;拥有独特的元素&#xff0c;象征公平、革命和永不放弃的精神。此次…

遥感影像处理(ENVI+ChatGPT+python+ GEE)处理高光谱及多光谱遥感数据

遥感技术主要通过卫星和飞机从远处观察和测量我们的环境&#xff0c;是理解和监测地球物理、化学和生物系统的基石。ChatGPT是由OpenAI开发的最先进的语言模型&#xff0c;在理解和生成人类语言方面表现出了非凡的能力。本文重点介绍ChatGPT在遥感中的应用&#xff0c;人工智能…

高性能的key-value数据库Redis 介绍

Redis 是一个高性能的key-value数据库。 Redis是一个开源的键值存储系统&#xff0c;通常用于缓存和消息传递。它支持多种类型的数据结构&#xff0c;如字符串、列表、集合、散列表和有序集合等。Redis的特点是提供了高性能、灵活性和可伸缩性。 Redis的主要特点包括&#xff…

数据结构之二叉树的精讲

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

【MicroPython】SPI层次结构SPI协议与SPI控制器结构

文章目录 前言一、SPI 程序层次1.1 硬件原理图1.2 硬件框图1.3 软件层次 二、SPI协议2.1 硬件连线2.2 如何访问SPI设备2.3 SPI 框图 总结 前言 SPI&#xff08;Serial Peripheral Interface&#xff09;是一种常见的串行通信协议&#xff0c;用于在微控制器和外部设备之间进行…

Redis 【1】—— 安装 与 配置

Redis 【1】—— 安装 与 配置 一、安装 与 配置&#xff08;一&#xff09;使用 yum 安装&#xff08;二&#xff09;创建符号链接1. 软链接2. 相关指令 &#xff08;三&#xff09;修改配置文件&#xff08;四&#xff09;Redis 的启停 一、安装 与 配置 &#xff08;一&…

华为配置WLAN高密业务示例

配置WLAN高密业务示例 组网图形 图1 配置高密WLAN环境网络部署组网图 业务需求组网需求数据规划配置思路配置注意事项操作步骤配置文件 业务需求 体育场由于需要接入用户数量很大&#xff0c;AP间部署距离较小&#xff0c;因此AP间的干扰较大&#xff0c;可能导致用户上网网…