Android内存溢出的相关问题

来源:互联网 发布:linux ftp 指定ip登录 编辑:程序博客网 时间:2024/05/18 17:56

一直以来,对于菜鸟的我开发Android程序的时候,从来不会考虑内存溢出相关问题,总认为JAVA有那么好的内存管理机制,我还用考虑这个?是的!到了不得不考虑的时候了,最近开发的程序,代码越来越多,问题自然越来越多。其中最大的问题就是一个:内存溢出,直接导致程序死掉,于是找了一些资料,了解了一些关于这个问题。

我只是找了一些常见的,非常常用的一些情况,如果哪里有需要改进的地方,或者说的不对的地方,还请大家留言,我们一起改进。

Android代码中可能引起内存泄露的地方:

1、查询数据库以后没有关闭游标Cursor

2、Bitmap对象不再使用的时候,没有调用recycle()释放内存

3、对于定义的对象的引用没有及时释放

4、构造Adapter时,没有使用缓存的convertView

5、盲目使用静态变量、类变量

6、进行文件操作时,没有及时关闭流

7、设置广播接收器的时候,没有及时取消注册,包括设置各种监听器的时候,没有及时取消注册

下面关于每个点详细解释一下:

1、查询数据库是很多应用都要做的事情,与SQLite进行数据交互,增删改查操作非常普遍,但是如果查询数据库后没有及时关闭游标Cursor,将会产生一些不必要的麻烦。

示例代码:

Cursor cursor = sqlite.getReadableDatabase().query("user",null,null,null,null);

if(cursor.moveToNext()){

.......

}

修改后的代码:

Cursor cursor = null;

try{

cursor = sqlite.getReadableDatabase().query("user",null,null,null,null);

if(cursor != null && cursor.moveToNext()){

......

}

}finally{

if(cursor != null){

try{

cursor.close();

}cathe(Exception e){

//.....

}

}

}

2、这个问题看似不起眼,也许你加载一幅图两幅图没发现有什么问题,当你的程序反复调用Bitmap的时候,如果没有及时释放,将会发生意想不到的错误。

如果一个Bitmap对象不再使用的时候,一定要调用Bitmap.recycle()方法,一般我们放在onDestroy()方法中。

3、关于对象引用释放的问题,一般情况是不会有什么太大问题,但是随着工程的扩大,后面的隐患将会非常大,当然,为了增强我们代码的健壮性,这些细节问题还是必须要注意的。

示例代码:

Intent intent = new Intent(MainActivity.this,Second.class);

startActivity(intent);

修改后的代码:

Intent intent = new Intent(MainActivity.this,Second.class);

startActivity(intent);

intent = null;

类似这样的对象引用记得要用完就释放,慢慢养成一个良好的编程习惯。

4、构造Adapter时,没有使用缓存的convertView,以构造ListView的BaseAdapter为例,在BaseAdapter中提高了方法:

public View getView(int position, View convertView, ViewGroup parent)来向ListView提供每一个item所需要的view对象,初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会把这些view对象缓存起来,向上滚动ListView时,原先位于最上面的lsit item的view对象会被回收,然后用来构造新出现的下面的item,这个过程就是getView()完成的,第二个形参View convertView就是被缓存起来的list item的view对象。

由此可以看出,不用convertView的话,每次getView都会实例化一个View对象,非常浪费内存和时间。

示例代码:

public View getView(int position, View convertView, ViewGroup parent){

View view = new Xxx(...);

...

return view;

}

修改后的代码:

public View getView(int position, View convertView, ViewGroup parent){

View view = null;

if(convertView != null){

view = convertView;

populate(view.getItem(position));

...

}else{

view = new Xxx();

...

}

return view;

}

5、用static来修饰一个变量的时候,那么该变量就是该类,而不是该类的示例,所以用static修饰的变量,生命周期非常长,如果用它引用一些非常耗资源的实例,就要谨慎对待,我们的原则是:能用局部变量不用全部变量,能用全局变量不用静态变量。

6、在使用文件或者访问网络资源时,使用了InputStream/OutputStream也会导致内存泄露,记得及时关闭

7、设置广播接收器:

public class ActivityReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {

}

}

activityReceiver = new ActivityReceiver();
IntentFilter filter = new IntentFilter();
filter.addActionintent);
registerReceiver(activityReceiver, filter);

记得要及时unregisterReceiver(activityReceiver);

当然,还有各种注册监听器的情况:

mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
public class MySensorListener implements SensorEventListener{
@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
}

listener = new MySensorListener();
lightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
mSensorManager.registerListener(listener, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);
记得及时要取消注册监听mSensorManager.unregisterListener(listener);

今天就说到这里,后面再实践中还有什么总结的继续搬上来。


参考链接:

http://blog.csdn.net/bill_ming/article/details/7814841

http://blog.csdn.net/cyq1028/article/details/19980369

0 0