.NET虽然拥有强大易用的垃圾回收机制,但并不是因为这样,你就可以对资源管理放任不管,其实在稍不注意的时候,可能就造成了资源泄露,甚至因此导致系统崩溃,到那时再来排查问题就已经是困难重重。

==========  原创作品    作者:未闻    出处:博客园·布道阁  ==========

一、知识点简单介绍

常见的资源泄露有:

  • 内存泄漏:非托管资源没有释放、非静态对象注册了静态实例。
  • GDI泄露:字体。
  • 句柄泄露:Socket或线程。
  • 用户对象泄露:移除的对象未释放。

二、具体实例

1. 内存泄漏

很常见的现象是分不清哪些对象需要释放,对于控件、Stream等一些非托管资源也只管新增,却没有释放,功能是实现了,却埋了颗不小的雷。

private void button1_Click(object sender, EventArgs e)
{
for(int i=;i<;i++)
this.Controls.Add(new TabPage());
}
private void button1_Click(object sender, EventArgs e)
{
new Form2.ShowDialog();
}

如果你觉得写这样的代码很Cool,很简洁,你在项目中也有这么写代码,那你就碰到大麻烦了,你试试在上面Form2中开个大一点的数组来检查内存,然后运行,按几下按钮,你就会发现,内存一直增加,即使你调用了GC也无济于事。所以,对于此类非托管资源要记住释放,用完即废可以采用using关键字。

public Form2()
{
InitializeComponent();
MyApp.FormChanged += FormChanged;
}

上面这个例子中,MyApp是一个静态类,如果在实例对象中向这种类里面注册了事件,而又没有取消注册,这样也会遇到大麻烦,即使在外部已经记得调用了Form2的Dispose也是没用的。

解决方案

2. GDI泄露

一般会跟字体相关,例如我曾在Android上用Cocos2d做一个小游戏时频繁地切换字体、Dev控件的Font属性赋值也会有这种现象。

XXX.Font = new Font(...)

解决方案

  • 这个问题我目前是采用字体池来解决,类似线程池的概念,相同Key值取同一个对象。若有更好方案欢迎留言讨论

3. 句柄泄露

一般跟Socket和Thread(线程)有关

for(int i=;i<;i++){
new Thread(()=>{
Thread.Sleep();
}).Start();
}

解决方案

  • Socket的场景暂时没遇到。
  • 线程问题采用线程池相关的辅助类能有效解决,例如ThreadPool、Task、Parallel。

4. 用户对象泄露

一般跟移除的对象未释放有关

private void button1_Click(object sender, EventArgs e)
{
tab.Remove(tabPage);
}

三、最后特别奉送一个内存释放的大招

[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
/// <summary>
/// 释放内存
/// </summary>
public static void ClearMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -, -);
}
}

调用以上API能让你的内存一下爆减,是不是很给力,一调用内存就降下来了。But,先别高兴太早,这其实是伪释放,只是暂时解决内存大量泄漏导致系统崩溃的应急处理方案。具体原因参考:SetProcessWorkingSetSize函数的骗局,关键信息:物理内存转虚拟内存,涉及磁盘读写。好处坏处都贴出来了,是否需要使用请君自己斟酌。

四、总结

实际上由于各个开发人员的水平跟接触面不同,又没有经过统一的培训(各个人对资源释放的理解与关注度不同,或者写代码时就没考虑内存未被释放这种问题),发现问题的时候项目往往已经做到了一个阶段,系统也比较庞大了,这种时候才发现内存泄露的问题确实是很头疼的。

  • 资源泄露的场景往往是相互关联的,发生最多的就是内存泄漏,而除了写法可能有问题外,也可能是因为句柄泄露或用户对象泄露引起的。

五、参考资料

最新文章

  1. PHP环境搭建
  2. TreeView checkbox 全选
  3. c++学习--面向对象一实验
  4. 如何做好一个ORM框架
  5. java Base64算法的使用
  6. linux shell中判断bash脚本输入的参数个数
  7. 消息中间件Notify和MetaQ-阿里中间件
  8. 搭建PHP环境LAMP(Linux+Apache+MySQL+PHP)
  9. MS WORD 表格自己主动调整列宽,自己主动变美丽,依据内容自己主动调整
  10. Quartz.net使用记录
  11. asp 域名跳转
  12. mysql5.5 无法创建实例,error 16001
  13. WINFORM窗体里使用网页控件的一些办法
  14. PAT (Advanced Level) 1015. Reversible Primes (20)
  15. CentOS环境下中文显示乱码,vim和ls命令显示中文均为乱码的解决办法
  16. apollo客户端springboot实战(四)
  17. Django 安装 创建项目
  18. Nmap使用指南
  19. 线程安全的&quot;懒汉&quot;单例模式
  20. RESTframwork之视图view

热门文章

  1. 【阿里云IoT+YF3300】6.物联网设备报警配置
  2. 判断一字串String中是否包含某一串字符串
  3. vue事件双向绑定
  4. ES6对象简洁语法
  5. 转载:全面理解面向对象的 JavaScript
  6. 暑期集训20190807 游戏(game)
  7. 在线热备份数据库之innobackupex 完整备份InnoDB
  8. [考试反思]0809NOIP模拟测试15:解剖
  9. Redis持久化--Redis宕机或者出现意外删库导致数据丢失--解决方案
  10. [转载]2.7 UiPath Flowchart的介绍和使用