内存泄漏是指程序在运行过程中,由于某些原因导致程序无法释放已经不再使用的内存,使得这部分内存持续被占用,最终可能导致系统可用内存逐渐减少,严重时会影响系统性能甚至导致程序崩溃。(内存泄漏是指程序中已经分配的内存由于各种原因(如对象引用未正确释放、资源未关闭等),无法被垃圾回收机制回收,而不是真正意义上的 "漏出去"。例如,在 C# 中,如果一个静态集合类持有了对象的引用,并且在对象不再使用时没有将其从集合中移除,那么这些对象占用的内存就无法被回收,这就是一种内存泄漏的情况。)
目录
静态集合类引起的内存泄漏
静态集合类(如 static List
、static Dictionary
等)的生命周期与应用程序的生命周期一致。如果将对象添加到静态集合中,并且在对象不再使用时没有从集合中移除,这些对象将一直被集合引用,无法被垃圾回收机制回收,从而造成内存泄漏。(解决办法:在对象不再需要时,主动从静态集合中移除该对象的引用,这样垃圾回收器就可以回收该对象占用的内存;使用弱引用的对象,这种对象可以被垃圾回收;使用过期策略的缓存,到了一定时间会自动回收)
未释放的资源
许多资源(如文件句柄、数据库连接、网络连接、图形设备上下文等)需要手动释放。如果在使用完这些资源后没有调用相应的 Dispose
方法(实现了 IDisposable
接口的对象)或 Close
方法来释放资源,会导致资源一直被占用,造成内存泄漏。更好的做法是使用 using
语句,它会自动调用 Dispose
方法。
事件订阅未取消
当一个对象订阅了另一个对象的事件时,订阅对象会持有对发布对象的引用。如果在订阅对象不再需要接收事件时,没有取消订阅,发布对象会一直持有订阅对象的引用,导致订阅对象无法被垃圾回收,造成内存泄漏。(为避免内存泄漏,应在合适的时候取消订阅)
内部类持有外部类引用
在 C# 中,非静态内部类会隐式持有外部类的引用。如果内部类的生命周期比外部类长,且没有正确处理这种引用关系,会导致外部类无法被垃圾回收,造成内存泄漏。(可采用使用静态内部类(使其不隐式持有外部类引用)、手动解除内部类对外部类的引用(在不再需要时将引用置为 null)、使用弱引用(让内部类对外部类的引用不阻止外部类被回收)等方法。)
缓存使用不当
如果在程序中使用缓存(缓存(Cache)是一种数据存储机制,它充当数据的临时存储区域,位于高速设备(如内存)中,用于减少对低速数据源(如磁盘、网络数据库等)的频繁访问,以此来提高数据访问的速度和系统的整体性能。很多情况下字典可以被看作是简单的缓存)来存储数据,并且没有合理的缓存清理策略,随着缓存数据的不断增加,会占用大量内存,导致内存泄漏。(可以通过设置缓存项的过期时间或最大容量限制来避免内存泄漏。)