目录
变量的回收
1. 局部变量
方法进栈,出栈,然后回收。
2. 成员变量
对象的回收而销毁。
3. 静态变量
静态成员不依赖与对象,而是属于类的,静态成员存放与方法区,且静态成员是共享与对象的
很多程序员的误区
class MyObject {
private static final MyObject INSTANCE = new MyObject();
private MyObject() {
System.out.println("MyObject 构造函数")
}
public static MyObject getInstance() {
return INSTANCE;
}
}
class Main {
public static void main(String[] args) {
//TODO
}
}
此时什么都没有输出,修改一下代码:
class Main {
public static void main(String[] args) {
MyObject.getInstance();
}
}
理所当然输出 : MyObject 构造函数
静态变量的回收
一、类装载时加载并初始化静态成员。
类什么时候被装载?
根据上面例子,类是在被调用时装载。比如:new Object() 时,调用类的静态成员时。构造方法也可以说是静态的。
二、静态变量随着类的卸载而销毁。
类什么时候被卸载?
进程结束时卸载类。
说明:一般情况下,所有的类都是默认的ClassLoader加载的,只要ClassLoader存在,类就不会被卸载,而默认的ClassLoader生命周期是与进程一致的。(来源网络)
三、Android 进程什么时候结束?
启动一个App再次点击back键后,此App 的线程会缓存到后台中,当然条件是内存足够的情况下,在内存不足时就有可能被kill掉。
后台缓存进程的好处是 (下次可以快速启动App)
当我们启动App退出App(此时没有手动清理内存)再次进入App,会发现上一次存在静态变量的数据和状态可能还存在,还有可能直接报空指针异常。因此要看具体情况进行清空操作。
四、单列模式对象 (Application)
Application 是一个单列对象,当App被启动时优先启动它,其生命周期是整个main进程。可以按需求自定义Application类,存放需要全局的静态变量,方便数据传递及使用。
五、Android 典型内存泄漏
static TextView textTv;
textTv = new TextView(context);
- 其静态的TextView持有一个活动上下文。
- 匿名内部类和非静态内部类默认持有外部类引用。(问题不大,避免对象被别的对象强引用)
- 单列模式对象持有上下文。 (禁止单列引用上下文)
- 静态比活动的生命周期要长,活动出栈后执行了一遍生命周期,等待系统回收,可是因为被静态强引用的后则在引用链可达性范围,因此导致在这个时间要被回收的对象无法回收,造成整个活动无法销毁而内存泄漏。
- 线程造成的内存泄漏。AsyncTask 、Thread 和 TimerTask 也可能导致 Activity 泄漏。只要它们是通过匿名类创建的,尽管它们在单独的线程被执行,它们也会持有对 Activity 的强引用,进而导致内存泄漏。
- 资源未关闭或未调用回收方法造成的内存泄漏。打开一个文件时,未关闭 (closed) 流对象。sqlite,打开数据库时未关闭,获取了一个游标对象未关闭。自定义view时,在加载Attr时一般使用TypedArray工具类,往往会遗漏调用recycle()方法。
- Handler,在处理发送来的消息持有上下文时,此时消息未被及时处理,发送者已经回调收回方法,因为消息队列信息对象强引用调用者上下文,导致调用者无法回收。
一旦进程被kill掉,此App分配的内存都将清空。
End
希望大家看了这篇文章能减少bug
以下是深入了解的链接导航