.NET中常见的内存泄漏和解决办法
在.NET中,虽然CLR的GC垃圾回收器帮我们自动回收托管堆对象,释放内存,最大程度避免了"内存泄漏"(应用程序所占用的内存没有得到及时释放),但.NET应用程序"内存泄漏"的问题还是会存在,如果不加以注意,"内存泄漏"时有发生。
有关流以及Reader或Writer引起的内存泄漏
比如,把文件读取到流中:
public static string ReadFile(){var filePath = @"硬盘地址";var sr = new StreamReader(filePath);return sr.ReadToEnd();}
以上,StreamReader在读取数据后没有解释销毁,存在"内存泄漏"。正确的做法是在使用完后及时关闭。
public static string ReadFile(){var filePath = @"硬盘地址";using(var sr = new StreamReader(filePath)){return sr.ReadToEnd();}}
或者
public static string ReadFile(){var filePath = @"硬盘地址";var sr = new StreamReader(filePath);var result = sr.ReadToEnd();sr.Close();return result;}
以上,需要我们注意的是:当通过某种流的构造函数创建的对象实例,注意及时关闭。
有时候,通过某个方法返回某种流的对象实例,也会忘记关闭。比如以下:
//创建字节数组var data = new byte[1024];var client = new TcpClient();//从TCP实例方法返回流var stream = client.GetStream();//把流读到字节数组中int bytesLength = stream.Read(data, 0, data.Length);//字节数组转换城字符串var result = System.Text.Encoding.ASCII.GetString(data, 0, bytesLength);
正确的写法应该是:
//创建字节数组var data = new byte[1024];var client = new TcpClient();//从TCP实例方法返回流var stream = client.GetStream();//把流读到字节数组中int bytesLength = stream.Read(data, 0, data.Length);stream.Close();//字节数组转换城字符串var result = System.Text.Encoding.ASCII.GetString(data, 0, bytesLength);
同理,其它与流有关的类,我们也需要注意在用完后及时关闭:
● FileStream
● MemoryStream
● StreamReader
● TextWriter
......
静态引用引起的内存泄漏
对于静态实例来说,除非应用程序关闭,对应的内存一直得不到释放。比如有如下遵循"Siingleton"模式的类(没考虑线程安全)。
public class MySingletonClass{private static MySingletonClass myInstance;private static List<IAmBig> bigObjects = new List<IAmBig>();private MySingletonClass(){}public static MySingletonClass MyInstance{get{if(myInstance == null){myInstance = new MySingletonClass();}return myInstance;}}public static IAmBig CreateBigObject(){var bigObject = new IAmBig();bigobject.AllocateMemory(4096);bigObjects.add(bigObject);return bigObject;}}public class IAmBig{}
以上,每次调用CreateBigObject静态方法,都往List<IAmBig>类型集合中添加,由于MySingletonClass静态类实例一直存在于应用程序的生命周期,再加上GC不会释放bigObjects这个集合对象实例,于是就出现了"内存泄漏"。解决办法是避免让静态实例引用其它实例对象,避免出现静态实例的链式引用。
委托引起的内存泄漏
比如有2个委托形成的委托链。
var objectOne = new ObjectOne();var objectTwo = new ObjectTwo();objectOne.StateChanged += objectTwo.StateChangedEventHandler;objectTwo.Dispose();
以上,把objectTwo的委托注册给了objectOne,这样objectOne和objectTwo有依赖关系,形成了依赖链。只有当objectOne被释放,才能释放objectTwo。如果objectOne恰巧是全局静态实例,那在应用程序的生命周期内,objectTwo一直得不到内存释放,造成了"内存泄漏"。
解决办法是在调用objectTwo的Dispose方法之前,先解开两者的依赖关系。修改如下:
var objectOne = new ObjectOne();var objectTwo = new ObjectTwo();objectOne.StateChanged += objectTwo.StateChangedEventHandler;......objectOne.StateChanged -= objectTwo.StateChangedEventHandler;objectTwo.Dispose();
非托管资源引起的内存泄漏
public class MyUnManagedExample{public void Allocate(){IntPtr pointer = Marshal.AllocHGlobal(1024);}}
对于创建的非托管类型的实例ponter,需要显式释放。
Marshal.FreeGlobal(pointer);
实现IDisposable接口的类引起的内存泄漏
所有实现IDisposable接口的类都有一个Dispose方法,如果忘记调用,就造成"内存泄漏"。
相关文章
- 使用 .NET Core 的日志记录
- delphi调用webservice (.NET C#版)
- ASP.NET Core之多语言配置
- .NET Core开源Quartz.Net作业调度框架实战演练
- .NET开源Protobuf-net组件葵花手册
- PhpExcel导出excel报错:net::ERR_INVALID_RESPONSE
- C#.NET常见问题(FAQ)-如何把文本复制粘贴到文本框的光标位置
- [ASP.NET Core 3框架揭秘] 依赖注入[3]:依赖注入模式
- .NET Core采用的全新配置系统[5]: 聊聊默认支持的各种配置源[内存变量,环境变量和命令行参数]
- Aitit 认证体系之道 attilax著艾龙著 1. 认证体系分类2 1.1. 按照语言来分 java net php2 1.2. 按照平台来分 web cs 桌面2 1.3. 综合性认证
- VB.net:VB.net编程语言学习之基于VS软件连接SQL Server(利用ADO.NET操作数据库/添加新数据源/DataGridView数据表格控件)的简介、案例应用之详细攻略
- Net Core 微服务 - 如何在docker容器里运行一个简单的.net core web api 服务
- 定时执行的任务Quartz.net
- Dynamsoft Label Recognizer SDK FOR .CPP.NET
- Dynamsoft Dynamic .NET TWAIN for net Crack
- ASP.NET Core微服务(六)——【.Net Core操作redis】StackExchange.Redis
- net core HTTP Error 500.31 - Failed to load ASP.NET Core runtime HTTP Error 500.30
- 在.NET Core Web API 中应用 Swagger
- .NET/C#/MSSQL面试题混谈
- 关于ASP.net开启身份验证时集成的托管管道模式下不适用的 ASP.NET 设置