一、首先以一个内存泄露实例来开始本节基础概念的内容:
实例1:(单例导致内存对象无法释放而泄露)
可以看出ImageUtil这个工具类是一个单例,并引用了activity的context。
试想这个场景,应用起来以后,转屏。转屏以后,旧MainActivity会destroy,新MainActivity会重建,导致单例ImageUtil重新getInstance。很不幸的是,由于instance已经不是空的了,所以ImageUtil不会重建,还持有之前的Context,也就是之前的那个MainActivity实例的context,因此会造成两个问题:
功能问题:使用ImageUitl访问context相关内容时可能会发生异常(因为当前context并不是当前activity的context);
内存泄露:旧context被生命周期更长的静态变量持有而导致activity无法释放造成泄漏!(因此静态变量是很容易因此内存泄露的!)
使用工具可以看到ImageUtil引用了MainActivity导致MainActivity驻留内存发生泄漏。
备注:本系列部分概念和例子引用来自网络。
二、内存泄露,我们要研究的泄露对象到底是什么?
首先我们来了解程序运行时,所需内存的分配策略:按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的,对应的,三种存储策略使用的内存空间主要分别是静态存储区(也称方法区)、堆区和栈区。他们的功能不同,对他们使用方式也就不同。
静态存储区(方法区):内存在程序编译的时候就已经分配好,这块内存在程序整个运行期间都存在。它主要存放静态数据、全局static数据和常量。
栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分