Android 手机给应用分配的堆内存通常是8 M 左右, 如果内存处理不当很容易造成 OOM (OutOfMemoryError),OOM 主要由于一下这些原因引起的:
1. 数据库 Cursor 没有关闭。
当我们使用完数据库之后,一定要调用 close() 关闭数据库,并释放资源。
2. ListView 等列表没有使用 ViewHolder 。
1 @Override 2 public View getView(int position, View convertView, ViewGroup parent) { 3 ViewHolder vHolder = null; 4 //如果convertView对象为空则创建新对象,不为空则复用 5 if (convertView == null) { 6 convertView = inflater.inflate(..., null); 7 // 创建 ViewHodler 对象 8 vHolder = new ViewHolder(); 9 vHolder.img= (ImageView) convertView.findViewById(...); 10 vHolder.tv= (TextView) convertView 11 .findViewById(...); 12 // 将ViewHodler保存到Tag中 13 convertView.setTag(vHolder); 14 } else { 15 //当convertView不为空时,通过getTag()得到View 16 vHolder = (ViewHolder) convertView.getTag(); 17 } 18 // 给对象赋值,修改显示的值 19 vHolder.img.setImageBitmap(...); 20 vHolder.tv.setText(...); 21 return convertView; 22 } 23 24 static class ViewHolder { 25 TextView tv; 26 ImageView img; 27 }
3. 未取消注册广播接收器。
registerReceiver() 和 unregisterReceiver() 必须成对使用, 通常是在 onDestory () 方法中取消注册广播接收器。
4. IO流未及时关闭。
5. Bitmap 使用后未调用 recycle()。
6. 线程也是造成内存泄漏的一个重要源头。线程产生内存泄漏主要是由于线程的生命周期不可控。我们来看看下面这段代码:
1 public class MyActivity extends Activity { 2 @Override 3 public void onCreate(Bundle savedInstanceState) { 4 super.onCreate(savedInstanceState); 5 setContentView(R.layout.main); 6 new MyThread().start(); 7 } 8 private class MyThread extends Thread{ 9 @Override 10 public void run() { 11 super.run(); 12 //耗时的操作 13 } 14 } 15 }
假设MyThread 的 run 函数是一个很费时的操作,当调用 finish 的时候 Activity 会被销毁掉吗? 事实上 , MyThread 是Activity的内部类,所以 MyThread 中保存了 Activity 的一个引用,当 run 方法没有执行完之前, MyThread 是不会被销毁的,因此它所引用的Activity 也不会被销毁,因此就出现了内存泄露问题。
7. 单例造成的内存泄漏。由于单例模式的静态特性是的生命周期跟应用程序的生命周期一样长,因此很容易由于使用不当造成内存泄漏。例如:
1 public class AppManager {
2 private static AppManager instance;
3 private Context context;
4 private AppManager(Context context) {
5 this.context = context;
6 }
7 public static AppManager getInstance(Context context) {
8 if (instance != null) {
9 instance = new AppManager(context);
10 }
11 return instance;
12 }
13 }
这里如果传入的是 Activity 的 Context ,当该Context的Activity退出后,但是由于 Context 被单利对象引用,所以导致 Activity 无法被回收,就造成了内存泄漏。
8. 创建一个非静态内部类的静态实例造成的内存泄漏。
public class MainActivity extends AppCompatActivity {
private static TestResource mResource = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(mManager == null){
mManager = new TestResource();
}
//...
}
class TestResource {
//...
}
}
因为非静态内部类会持有外部类的引用,而该非静态内又创建了一个静态实例,该静态实例的生命周期与应用的生命周期一样长,这就导致了静态实例一直会持有 Activity 的引用而造成的内存泄漏。