在.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中常见的内存泄漏和解决办法的更多相关文章

  1. android中常见的内存泄漏和解决的方法

    android中的内存溢出预计大多数人在写代码的时候都出现过,事实上突然认为工作一年和工作三年的差别是什么呢.事实上干的工作或许都一样,产品汪看到的结果也都一样,那差别就是速度和质量了. 写在前面的一 ...

  2. Android开发常见的Activity中内存泄漏及解决办法

    上一篇文章楼主提到由Context引发的内存泄漏,在这一篇文章里,我们来谈谈Android开发中常见的Activity内存泄漏及解决办法.本文将会以“为什么”“怎么解决”的方式来介绍这几种内存泄漏. ...

  3. Android中常见的内存泄漏

    为什么会产生内存泄漏? 当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏. ...

  4. Android性能优化之利用LeakCanary检测内存泄漏及解决办法

    前言: 最近公司C轮融资成功了,移动团队准备扩大一下,需要招聘Android开发工程师,陆陆续续面试了几位Android应聘者,面试过程中聊到性能优化中如何避免内存泄漏问题时,很少有人全面的回答上来. ...

  5. Js中常见的内存泄漏场景

    常见的内存泄漏场景 内存泄漏Memory Leak是指程序中已动态分配的堆内存由于疏忽或错误等原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果.内存泄漏并非指内 ...

  6. AFNetworking 3.0中调用[AFHTTPSessionManager manager]方法导致内存泄漏的解决办法

    在使用AFNetworking3.0框架,使用Instruments检查Leaks时,检测到1000多个内存泄漏的地方,定位到 [AFHTTPSessionManager manager] 语句中,几 ...

  7. Swift代理造成内存泄漏的解决办法

    在swift中,使用代理 ,可能很多人会这样实现: .首先定义一份协议. protocol ToolProrocol{ //代理方法 func didRecieveResults(result:Int ...

  8. JS 调试中常见的报错的解决办法

    报错:Uncaught SyntaxError: Unexpected token o in JSON at position 1 at JSON.parse (<anonymous>) ...

  9. css中常见margin塌陷问题之解决办法

    塌陷问题 当两个盒子在垂直方向上设置margin值时,会出现一个有趣的塌陷现象. ①垂直并列 首先设置两个DIV,并为其制定宽高 1 /*HTML部分*/ 2 <body> 3 <d ...

随机推荐

  1. android休眠唤醒驱动流程分析【转】

    转自:http://blog.csdn.net/hanmengaidudu/article/details/11777501 标准linux休眠过程: l        power managemen ...

  2. Memcached实战之复制----基于repcached的主从【转】

    由于 Memcached 自己没有防止单点的措施,因为为了保障 Memcached 服务的高可用,我们需要借助外部的工具来实现高可用的功能.本文引入 Repcached 这个工具,通过使用该工具我们可 ...

  3. 不能访问本地服务器场。没有注册带有FeatureDependencyId 的 Cmdlet

      不能访问本地服务器场.没有注册带有FeatureDependencyId 的 Cmdlet. 原因: 我有两个域管理员账号,分别:sp\administrator,sp\spadmin 其中后者才 ...

  4. (maven项目)使用java -jar命令遇到的小问题|xx.jar中没有主清单或Error:Invalid or corrupt jarfile xx.jar

    xx.jar中没有主清单或Error:Invalid or corrupt jarfile xx.jar 遇到这个问题,是因为你的jar包没有设置主类的入口. 即在META-INF文件夹的MANIFE ...

  5. Java基础86 MySQL数据库基础知识

    本文知识点(目录): 1.MySQL数据库的概述    2.MySQL数据库的管理[对数据库的操作](查询.删除.创建数据库,以及查询和修改数据库的编码模式)    3.表的管理[对数据库 表的操作] ...

  6. Java 基本语法---Java方法

    Java 基本语法---Java方法 0.概述 方法:就是用来解决一类问题的代码的有序组合,是一个功能模块: 在方法部分,只使用对象名词调用方法: Scanner sc = new Scanner(S ...

  7. 关于vim复制剪贴粘贴命令的总结

    最近在使用vim,感觉很好很强大,但是在使用复制剪切粘贴命令是,碰到了一些小困惑,网上找了一些资料感觉很不全,讲的也不好,遂自己进行实践并总结了. 首先是剪切(删除): 剪切其实也就顺带删除了所选择的 ...

  8. ansible源码解读

    Ansible源码获取 Ansible Github:https://github.com/ansible Ansible目录结构 $ tree -L 2 ansible-2.0.0.0 ansibl ...

  9. .NetCore 分布式日志收集Exceptionless 在Windows下本地安装部署及应用实例

    自己安装时候遇到很多问题,接下来把这些问题写出来希望对大家有所帮助 搭建环境: 1.下载安装 java 8 SDK (不要安装最新的10.0) 并配置好环境变量(环境变量的配置就不做介绍了) 2.下载 ...

  10. 如何用prometheus监控k8s集群中业务pod的metrics

    一般,我们从网上看到的帖子和资料, 都是用prometheus监控k8s的各项资源, 如api server, namespace, pod, node等. 那如果是自己的业务pod上的自定义metr ...