什么情况下会导致内存泄露

时间:2022-02-12 16:23:01
下面说明几点可能导致内存泄露的原因,供大家参考。
1.对象内存过大
保存了多个好用内存过大的对象,造成内存超出限制。
2.资源释放
程序代码的问题,长期保持某些资源,如Context,Cursor,IO流的引用,资源得不到释放造成内存泄露。
这里介绍几种情况:
2.1.数据库的cursor没有关闭。  
操作Sqlite数据库时,Cursor是数据库表中每一行的集合,Cursor提供了很多方法,可以很方便的读取数据库中的值,      可以根据索引,列名等获取数据库中的值,通过游标的方式可以调用moveToNext()移到下一行 
    当我们操作完数据库后,一定要记得调用Cursor对象的close()来关闭游标,释放资源。 
2.2构造adapter没有使用缓存contentview。 
    在继承BaseAdapter时会让我们重写getView(int position, View   convertView, ViewGroup parent)方法, 
    第二个参数convertView就是我们要用到的重用的对象 
Java代码  什么情况下会导致内存泄露
  
  
  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.        //将显示的View 包装成类  
  24. static class ViewHolder {  
  25.     TextView tv;  
  26.     ImageView img;  
  27. }  

    这里只讲使用方法,具体性能测试文章请见: 
    ListView中getView的原理+如何在ListView中放置多个item 
    http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html 
    Android开发之ListView适配器(Adapter)优化 
    http://shinfocom.iteye.com/blog/1231511 
2.3.调用registerReceiver()后未调用unregisterReceiver().  
     广播接收者(BroadcastReceiver)经常在应用中用到,可以在多线程任务完成后发送广播通知UI更新,也可以接收系统广播实现一些功能 
     可以通过代码的方式注册: 
    IntentFilter postFilter = new IntentFilter(); 
    postFilter.addAction(getPackageName() + ".background.job"); 
    this.registerReceiver(receiver, postFilter); 
    当我们Activity中使用了registerReceiver()方法注册了BroadcastReceiver,一定要在Activity的生命周期内调用unregisterReceiver()方法取消注册 
    也就是说registerReceiver()和unregisterReceiver()方法一定要成对出现,通常我们可以重写Activity的onDestory()方法: 
Java代码  什么情况下会导致内存泄露
  
  
  1. @Override  
  2. protected void onDestroy() {  
  3.       this.unregisterReceiver(receiver);  
  4.       super.onDestroy();  
  5. }  

2.4.未关闭InputStream/OutputStream。  
    这个就不多说了,我们操作完输入输出流都要关闭流 
2.5.Bitmap使用后未调用recycle()。  
    图片处理不好是造成内存溢出的又一个头号原因,(在我们的产品中也有体现), 
    当我们处理完图片之后可以通过调用recycle()方法来回收图片对象
Java代码  什么情况下会导致内存泄露

  
  
    1. if(!bitmap.isRecycled())  
    2. {  
    3.     bitmap.recycle()  
    4. }          

    除此之外: 
    直接使用ImageView显示bitmap会占用较多资源,特别是图片较大的时候,可能导致崩溃。 
    使用BitmapFactory.Options设置inSampleSize, 这样做可以减少对系统资源的要求。 
    属性值inSampleSize表示缩略图大小为原始图片大小的几分之一,即如果这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片大小就为原始大小的1/4。 
        BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();  
        bitmapFactoryOptions.inJustDecodeBounds = true;  
        bitmapFactoryOptions.inSampleSize = 2;  
        // 这里一定要将其设置回false,因为之前我们将其设置成了true  
        // 设置inJustDecodeBounds为true后,decodeFile并不分配空间,即,BitmapFactory解码出来的Bitmap为Null,但可计算出原始图片的长度和宽度  
        options.inJustDecodeBounds = false; 
        Bitmap bmp = BitmapFactory.decodeFile(sourceBitmap, options);  

3.static关键字的使用
static 是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例,就可能会造成内存的泄露。
针对static的解决方案:
应该尽量避免static成员变量引用资源耗费过多的实例,比如Context.
Context尽量使用ApplicationContext的生命周期比较长,引用它不会出现内存泄露。
使用WeakReference代替强引用。比如可以使用WeakReference<Context> mContext;
4.线程导致内存溢出
线程产生内存泄露的主要原因在于线程生命周期的不可控。如当我们切换横竖屏的时候,一般会重新创建Activity,老的Activity应该被销毁。但是此时我们在子线程中正在进行耗时的操作,老的Activity不会被销毁,这个时候就会出现内存泄露。
解决方案:
将线程的内部类,改为静态内部类。
在线程内部采用弱引用保存Context引用。