php redis 内存溢出,造成OOM(内存溢出)的几种情况

数据库Cursor没关。

当我们操作完数据库后,一定要调用close()释放资源。

构造Adapter没有使用缓存ContentView。

@Override

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

ViewHolder vHolder = null;

//如果convertView对象为空则创建新对象,不为空则复用

if (convertView == null) {

convertView = inflater.inflate(..., null);

// 创建 ViewHodler 对象

vHolder = new ViewHolder();

vHolder.img= (ImageView) convertView.findViewById(...);

vHolder.tv= (TextView) convertView

.findViewById(...);

// 将ViewHodler保存到Tag中

convertView.setTag(vHolder);

} else {

//当convertView不为空时,通过getTag()得到View

vHolder = (ViewHolder) convertView.getTag();

}

// 给对象赋值,修改显示的值

vHolder.img.setImageBitmap(...);

vHolder.tv.setText(...);

return convertView;

}

static class ViewHolder {

TextView tv;

ImageView img;

}

未取消注册广播接收者

registerReceiver()和unregisterReceiver()要成对出现,通常需要在Activity的onDestory()方法去取消注册广播接收者。

IO流未关闭 注意用完后及时关闭

Bitmap使用后未调用recycle()。

Context泄漏 这是一个很隐晦的OutOfMemoryError的情况。先看一个Android官网提供的例子:

private static Drawable sBackground;

@Override

protected void onCreate(Bundle state) {

super.onCreate(state);

TextView label = new TextView(this);

label.setText("Leaks are bad");

if (sBackground == null) {

sBackground = getDrawable(R.drawable.large_bitmap);

}

label.setBackgroundDrawable(sBackground);

setContentView(label);

}

这段代码效率很快,但同时又是极其错误的:

我们看一下setBackgroundDrawable(Drawable background)的源码:

public void setBackgroundDrawable(Drawable background) {

...

background.setCallback(this);

}

有background.setCallback(this);方法,也就是说Drawable拥有TextView的引用,而TextView又拥有Activity(Context类型)的引用, 因为sBackground为static的,即使Activity被销毁,但是sBackground的生命周期还没走完,所以内存仍然不会被释放。这样就会有内存泄露了。 对,这样想是对的,但是我们看一下setCallback的源码:

public final void setCallback(Callback cb) {

mCallback = new WeakReference(cb);

}

我们会发现里面使用了WeakReference,所以不会存在内存泄露了,但是官网当时提供的例子明明说有泄露,这是因为在3.0之后, 修复了这个内存泄露的问题,在3.0之前setCallback,方法是没有使用WeakReference的,所以这种泄露的情况在3.0之前会发生,3.0之后已经被修复。

线程 线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控。我们来考虑下面一段代码。

public class MyActivity extends Activity {

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

new MyThread().start();

}

private class MyThread extends Thread{

@Override

public void run() {

super.run();

//耗时的操作

}

}

}

假设MyThread的run函数是一个很费时的操作,当调用finish的时候Activity会销毁掉吗?

事实上由于我们的线程是Activity的内部类,所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,MyThread是不会被销毁的, 因此它所引用的Activity也不会被销毁,因此就出现了内存泄露的问题。

尽量使用ApplicationContext Context引用的生命周期超过它本身的生命周期,也会导致Context泄漏。 所以如果打算保存一个长时间的对象时尽量使用Application这种Context类型。 例如:

mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);

改成:

mStorageManager = (StorageManager) getApplicationContext().getSystemService(Context.STORAGE_SERVICE);

按道理来说这种系统服务是不会有问题,但是有些厂商在修改的时候,可能会导致Context无法被及时释放。

Handler的使用,在Activity退出的时候注意移除(尤其是循环的时候)

public class ThreadDemo extends Activity {

private static final String TAG = "ThreadDemo";

private int count = 0;

private Handler mHandler = new Handler();

private Runnable mRunnable = new Runnable() {

public void run() {

//为了方便 查看,我们用Log打印出来

Log.e(TAG, Thread.currentThread().getName() + " " +count);

//每2秒执行一次

mHandler.postDelayed(mRunnable, 2000);

}

};

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

//通过Handler启动线程

mHandler.post(mRunnable);

}

}

这样在也会引发内存泄露。我们应该在onDestory方法中移除Handler,代码如下:

@Override

protected void onDestroy() {

super.onDestroy();

mHandler.removeCallbacks(mRunnable);

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值