内存溢出
抓狂的oom,这个错误抛出的原理
内存泄漏
当内存不足时,Android运行时就会触发GC,GC采用的垃圾标记算法为根搜索算法。内存泄漏就是指没有用的对象到GC root是可达的,导致GC无法回收该对象。
内存泄漏的场景
- 非静态内部类的静态实例,如
public class InnerActivity extends AppCompatActivity {
private static Object inner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inner);
//
inner=new InnerClass();
}
class InnerClass{}
}
静态实例inner生命周期与应用程序一样长,它持有InnerActivity的引用,导致InnerActivity无法被回收。
- 多线程相关的非静态内部类
public class InnerActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inner);
startAsyncTask();
}
void startAsyncTask(){
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... voids) {
while (true){//耗时任务
}
}
}.execute();
}
}
AsyncTask
的内部匿名类,如果线程不结束,则一直持有Activity的引用。我们可以会使用静态AsyncTask
或者退出Activity
时结束异步线程。
- Handler内存泄露
Handler
的Message
被存储在MessageQueue
中, 有些Message
不能立即处理,它们会在MessageQueue
存在很长时间,这会导致Handler无法被回收。如果Handler
是非静态的,则引用它的Activity
或Service
不能被回收。
解决方案:
- 一个是使用静态的
Handler
内部类,持有的引用使用弱引用 -
activity
的Destory
方法中,调用handler.removeCallbacksAndMessages(null)
;来移除MessageQueue
中的Message
.
未正确使用Context
对于不是必须使用Activity的Context情况,可以考虑使用Application Context来代替,特别是单例的情况。WebView
在应用中只要使用一次WebView,内存就不会被释放掉。通常的解决办法是为WebView单开一个进程,使用AIDL与应用进行通信。WebView可以根据业务需求在合适的时机进行销毁。
6.资源对象未关闭
资源对象比如Curso、File等,往往都使用了
内存分析
通过内存分析来发现泄漏点
避免内存抖动
频烦的内存申请及释放,会导致短时间的频烦GC,会严重影响程序性能。
解决方法:不要申请大量不必要的对象内存:
1, 不可变对象:String
2, 自动装箱:Integer, Boolean...
考虑使用对象池并缓存来减少内存抖动
留心enum类型的开销(一个指向枚举类型的引用就要占据4个字节)