欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-14 18:34:43
...
下面说明几点可能导致内存泄露的原因,供大家参考。
1.对象内存过大 
保存了多个好用内存过大的对象,造成内存超出限制。
2.资源释放
程序代码的问题,长期保持某些资源,如Context,Cursor,IO流的引用,资源得不到释放造成内存泄露。
1.对象内存过大 
保存了多个好用内存过大的对象,造成内存超出限制。
2.资源释放
程序代码的问题,长期保持某些资源,如Context,Cursor,IO流的引用,资源得不到释放造成内存泄露。
这里介绍几种情况:
	2.1.数据库的cursor没有关闭。  
  

操作Sqlite数据库时,Cursor是数据库表中每一行的集合,Cursor提供了很多方法,可以很方便的读取数据库中的值, 

    可以根据索引,列名等获取数据库中的值,通过游标的方式可以调用moveToNext()移到下一行 

<span style="color:#333333">    当我们操作完数据库后,一定要记得调用Cursor对象的close()来关闭游标,释放资源。 </span>
 
  
    在继承BaseAdapter时会让我们重写getView(int position, View   convertView, ViewGroup parent)方法, 
<span style="color:#333333">    第二个参数convertView就是我们要用到的重用的对象 </span>
 

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)优化 
<span style="color:#333333">    http://shinfocom.iteye.com/blog/1231511 </span>

 

2.3.调用registerReceiver()后未调用unregisterReceiver(). 
     广播接收者(BroadcastReceiver)经常在应用中用到,可以在多线程任务完成后发送广播通知UI更新,也可以接收系统广播实现一些功能 
     可以通过代码的方式注册: 
    IntentFilter postFilter = new IntentFilter(); 
    postFilter.addAction(getPackageName() + ".background.job"); 
    this.registerReceiver(receiver, postFilter); 
    当我们Activity中使用了registerReceiver()方法注册了BroadcastReceiver,一定要在Activity的生命周期内调用unregisterReceiver()方法取消注册 
<span style="color:#333333">    也就是说registerReceiver()和unregisterReceiver()方法一定要成对出现,通常我们可以重写Activity的onDestory()方法: </span>
 

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

  1. @Override  
  2. protected void onDestroy() {  
  3.       this.unregisterReceiver(receiver);  
  4.       super.onDestroy();  
  5. }  

 

2.4.未关闭InputStream/OutputStream。 
<span style="color:#333333">    这个就不多说了,我们操作完输入输出流都要关闭流 </span>

 

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; 
 
<span style="color:#333333">        Bitmap bmp = BitmapFactory.decodeFile(sourceBitmap, options);  </span>

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