C# 《编写高质量代码改善建议》整理&笔记 --(四)资源管理&序列化
1.显示释放资源需继承接口IDisposable
什么是资源:C#中每一个类型都代表一种资源,而资源又分为以下两类。
托管资源:由CLR管理分配和释放的资源,即从CLR里new出来的对象。
非托管资源: 不受CLR管理的对象,如windows内核对象,或者文件,数据块连接,套接字,COM对象等。
如果我们的类型使用到了非托管资源,或者需要显示地释放托管资源,那么需要让类型继承接口IDisposable。
相当于告诉调用者:类型对象时需要显示的释放资源的,你需要调用类型的Dispose方法。
public class AnotherClass:IDisposable
{
public void Dispose()
{
Dispose();
}
}
public class SampleClass:IDisposable
{
private IntPtr nativeResource = Marshal.AllocHGlobal();
private AnotherClass managedResource = new AnotherClass();
bool disposed = false;
public void Dispose()
{
Dispose();
GC.SuppressFinalize(this); //通知垃圾回收器不再调用析构器 } /// <summary>
/// 不是必要的,提供一个close方法仅仅为了更符合其他语言的规范。
/// </summary>
public void Close()
{
Dispose();
}
/// <summary>
/// 防止程序员忘记显示的调用Dispose
/// </summary>
~SampleClass()
{
Dispose();
} /// <summary>
/// 非密封类修饰用protected virtual
/// </summary>
/// <param name="isDisposing"></param>
protected virtual void Dispose(bool isDisposing)
{
if(disposed)
{
return;
} //清理托管资源
if(isDisposing)
{
if(managedResource!=null)
{
managedResource.Dispose();
managedResource = null;
}
} //清理非托管资源
if(nativeResource!=IntPtr.Zero)
{
Marshal.FreeHGlobal(nativeResource);
nativeResource = IntPtr.Zero;
}
disposed = true;
}
}
2.即使提供了显示释放资源,也应该在终结器中提供隐式清理
终结器(即析构函数),其意义在于我们不奢望类型的调用者会主动调用Dispose方法,基于终结器会被垃圾回收器调用
的特点,他被用于资源释放的补救措施。
如果调用者已经调用Dispose方法进行了显示地资源释放,那么隐式释放资源(终结器,析构函数)也就没必要运行了,
FCL中的类型GC提供了静态方法SupressFinalize来通知垃圾回收器。GC.SupressFinalize(this)
public class TestClass:IDisposable
{
public void Dispose()
{
Dispose();
GC.SuppressFinalize(this);//这样如果调用过,则不会再调用析构函数,如果不加,则还会调用析构函数
} ~TestClass() //写析构以防忘记调用Dispose的时候,自动调用该函数
{
Dispose();
}
}
3.何时及时释放资源
垃圾回收器什么时候进行回收工作?
1)系统具有较低的物理内存。
2)由托管堆上已分配的对象使用的内存超出了可接受的范围。
3)主动调用GC.Collect().
垃圾回收机制中海油一个“代”的概念。一共分为3代:0,1,2代。第0代包含一些短期生存的对象。如局部变量fileStream就是一个短期生存的对象。第一次执行fileStream就被丢到了第0代,但此刻不进行垃圾回收。当第0代满了的时候,运行时会认为现在低内存的条件已满足,那时才会垃圾回收。在回收之前,他实际没有用,却始终占据着内存不放,这对系统是极大的浪费,并且浪费还会干扰程序的正常运行。(始终占据文件资源,导致我们不能再次使用这个文件资源)
不及时释放资源还会带来另外一个问题:如果类型本身继承了IDisposable接口,垃圾回收机制虽然会自动帮我们释放资源,但是这个过程却延长了,因为它不是在一次回收中完成所有的清理工作。因为fileStream继承了IDisposable接口,故在第一次垃圾回收的时候,垃圾回收器会调用fileStream的终结器,然后等待下一次的垃圾回收,这时fileStream对象才可能被真正的回收掉。
4.必要时将不再使用的对象引用赋值为null
在执行垃圾回收时,类型的对象被回收时,类型的静态字段并没有被回收。
我们需要在析构函数中对这静态字段额外置为null。
在实际工作中,一旦我们感觉到自己的静态引用类型参数占用的内存空间比较大,并且用完不会再使用,便可以立刻将其赋值为null。(好习惯,因为静态变量,一旦创建,永远不会离开,还有尽量少使用静态变量。)
5.序列化
定义:把对象转变成流,称为序列化,反之,将流转变为对象称为反序列化。
用途:
①把对象保存到本地,在下次运行程序的时候,恢复这个对象。
②把对象传到网络中的另外一台终端上,然后在此终端还原这个对象。
③把对象复制到系统的粘贴板上,然后用Ctrl+V恢复这个对象。
1)为无用字段标注为不可序列化
①节省空间。类型在序列化后往往会存储到某个地方,如数据库,硬盘或内存中,如果一个字段在反序列化后不需要保持
状态,那就不应该被序列化,这会占用宝贵的空间资源。
C# 《编写高质量代码改善建议》整理&笔记 --(四)资源管理&序列化的更多相关文章
- C# 《编写高质量代码改善建议》整理&笔记 --(一)基本语言篇
		
题记:这是自己的观后感,工作两年了,本来打算好好学习设计模式,或者作为客户端深入了解GPU编程的,但是突然发现还有这么一本书. <编写高质量代码改善建议>,感觉这正是自己需要的. 我是做 ...
 - C# 《编写高质量代码改善建议》整理&笔记 --(六)编码规范及习惯
		
一.命名规范 1.考虑在命名空间中使用复数 System.AllCollections System.TheCollection 2.用名词和名词组给类型命名 ScoreManager UserCon ...
 - C# 《编写高质量代码改善建议》整理&笔记 --(五)成员设计
		
1.可以字段应该重构为属性 2.谨慎将数组或集合作为属性 数组和集合作为属性存在会引起这样的一个分歧:如果属性是只读的,我们通常会认为他是不可改变的.但是如果将只读属性应用于数组和集合,而元素的内容和 ...
 - C# 《编写高质量代码改善建议》整理&笔记 --(三)泛型&委托&事件
		
1.泛型 基于泛型,我们可以将类型参数化,以便更大范围地进行代码复用.同时,它减少了泛型类及泛型方法中的转型, 确保类型安全. 1)总是优先考虑泛型 优点:可重用性,类型安全,高效率. 2)避免在泛型 ...
 - C# 《编写高质量代码改善建议》整理&笔记 --(五)类型设计
		
1.区分接口和抽象类的应用场合 区别: ①接口支持多继承,抽象类则不能. ②接口可以包含方法,属性,索引器,事件的签名,但不能有实现,抽象类则可以. ③接口在增加新方法后,所有的继承者都必须重构,否则 ...
 - 编写高质量代码改善C#程序的157个建议——建议149:使用表驱动法避免过长的if和switch分支
		
建议149:使用表驱动法避免过长的if和switch分支 随着代码变得复杂,我们很容易被过长的if和switch分支困扰. 一个类枚举类型Week如下: enum Week { Monday, Tue ...
 - 编写高质量代码改善C#程序的157个建议——建议1:正确操作字符串
		
最近拜读了陆敏技老师的<编写高质量代码改善C#程序的157个建议>,感觉不错,决定把笔记整理一遍. 建议1: 正确操作字符串 字符串应该是所有编程语言中使用最频繁的一种基础数据类型.如果使 ...
 - 博友的    编写高质量代码 改善java程序的151个建议
		
编写高质量代码 改善java程序的151个建议 http://www.cnblogs.com/selene/category/876189.html
 - 编写高质量代码--改善python程序的建议(六)
		
原文发表在我的博客主页,转载请注明出处! 建议二十八:区别对待可变对象和不可变对象 python中一切皆对象,每一个对象都有一个唯一的标识符(id()).类型(type())以及值,对象根据其值能否修 ...
 
随机推荐
- java语言为什么能跨平台
			
参考https://blog.csdn.net/woailuo453786790/article/details/51660015 因为Java程序编译之后的代码不是能被硬件系统直接运行的代码,而是一 ...
 - 使用istream迭代器来输入输出数据
			
在C++中,很多人都会选择使用cin来进行数据的输入,使用cout来进行数据的输出,现在在C++11中我们可以使用iostream迭代器来进行这些操作,这会减少代码量,达到的效果和前面两种相同.以下是 ...
 - [Usaco2009 Jan]安全路经Travel BZOJ1576 Dijkstra+树链剖分+线段树
			
分析: Dijkstra求最短路树,在最短路树上进行操作,详情可见上一篇博客:http://www.cnblogs.com/Winniechen/p/9042937.html 我觉得这个东西不压行写出 ...
 - [Noi2016]区间 BZOJ4653 洛谷P1712 Loj#2086
			
额... 首先,看到这道题,第一想法就是二分答案+线段树... 兴高采烈的认为我一定能AC,之后发现n是500000... nlog^2=80%,亲测可过... 由于答案是求满足题意的最大长度-最小长 ...
 - angular开发环境配置全套教程
			
第一步.安装node.js 1.需要下载的文件路径:https://nodejs.org/en/download/ 2.安装nodejs: 3.验证node.js 4.npm安装以及验证: npm的安 ...
 - Vue之生命周期函数和钩子函数详解
			
在学习vue几天后,感觉现在还停留在初级阶段,虽然知道怎么和后端做数据交互,但是对对vue的生命周期不甚了解.只知道简单的使用,而不知道为什么,这对后面的踩坑是相当不利的.因为我们有时候会在几个钩子函 ...
 - netcore使用 jenkins + supervisor 实现standalone下多副本自动化发布
			
上一篇我们用jenkins做了一个简单的自动化发布,在shell中采用的是 BUILD_ID=dontKillMe nohup dotnet xxx.dll & 这种简单的后台承载,如果你的 ...
 - WPF自定义控件创建
			
WPF自定义控件创建 本文简单的介绍一下WPF自定义控件的开发. 首先,我们打开VisualStudio创建一个WPF自定义控件库,如下图: 然后,我们可以看到创建的解决方案如下: 在解决方案中,我们 ...
 - 产品管理开发之Git工作流和分支规范推荐
			
前言 无论是开源项目还是内部项目,使用Git都是大势所趋,尤其是在产品管理这块,使用Git大大提高了开发效率和产品的交付频率.本篇,针对Git的工作流和分支使用,进行了一些推荐. 目录 1 产 ...
 - 设计模式系列19:策略模式(Stragety Pattern)
			
定义 定义一系列算法,将它们一个个封装起来,并且使它们可以互相替换,该模式使得算法可独立于使用它的客户而变化. --<设计模式>GoF UML类图 使用场景 一个系统有许多类,而区分 ...