暂时写下我现在知道的,以后有更深的理解再补充,写的不对的欢迎留言指出。
查了一些资料,GC内存泄漏我觉得可以分为狭义的内存泄漏和广义的内存泄漏吧,狭义的泄漏是因为某些认为原因,GC未能履行其职责清除内存,比如编码的时候不小心忘记清除没用的静态共有对象,使得他一直占有没用内存。广义的泄漏就是真的就泄漏了,主要是非托管类型。
对于第一种情况我知道的几种泄漏的方式:
1、静态对象没有及时释放。静态对象在程序运行期间都占据内存。这个怎么说,我觉得除了一些工具类和管理器其他部分应该尽量避免静态字段吧,如果模块间要通过静态字段通讯,那耦合度肯定是有点高的。
2、事件。之前实习过看到框架各种OnDisable清除事件内的监听者,那时候可能搜索的姿势不对查不到什么资料,现在终于是明白了。事件导致的内存泄漏可以看一下这种情况:在函数中给全局事件添加一个监听者,甚至还引用了函数内的局部变量,因为C#中有闭包的机制,所以这个本应该在函数结束就被清除的局部变量会被写入监听者内部,也就是他是一直被引用了,如果忘记清除事件,这个引用将一直存在,导致所谓的内存泄漏。
3、多线程。每个线程分配了私有栈和内核栈,就算不用也是占据内存的。多线程的泄漏可以是开了一个无限运行的线程而且忘了关闭,自身堆栈占据内存,甚至线程可能是一个用来处理独立事件的线程,比如点击事件,每点击一次如果需要开启新的线程或者定义一些新的对象来存储数据,那么这个不仅是泄漏,而且泄漏的内存还会随点击的次数慢慢增大。
对于第二种情况:
主要是非托管类型,非托管类型可以通过实现IDisposable接口清除,如果使用终结器清除是有风险的。