android内存溢出解决

1,解决使用Bitmap时出现的内存溢出

1)及时的销毁,虽然,系统能够确认Bitmap分配的内存最终会被销毁,但是由于它占用的内存过多,所以很可能会超过java堆的限制。因此,在用完Bitmap时,要及时的recycle掉。recycle并不能确定立即就会将Bitmap释放掉,但是会给虚拟机一个暗示:“该图片可以释放了”。

2)设置一定的采样率,有时候,我们要显示的区域很小,没有必要将整个图片都加载出来,而只需要记载一个缩小过的图片,这时候可以设置一定的采样率,那么就可以大大减小占用的内存。如下面的代码:

private ImageView preview;  
BitmapFactory.Options options = new BitmapFactory.Options();  
options.inSampleSize = 2; 
Bitmap bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri), 
null, options);  
preview.setImageBitmap(bitmap);

3)运用软引用(SoftRefrence),有些时候,我们使用Bitmap后没有保留对它的引用,因此就无法调用Recycle函数。这时候巧妙的运用软引用,可以使Bitmap在内存快不足时得到有效的释放。如下例:

private class MyAdapter extends BaseAdapter {  

     private ArrayList mBitmapRefs = new ArrayList();  
     private ArrayList mValues;  
     private Context mContext;  
     private LayoutInflater mInflater;  

     MyAdapter(Context context, ArrayList values) {  
         mContext = context;  
         mValues = values;  
         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
     }  
     public int getCount() {  
         return mValues.size();  
     }  

     public Object getItem(int i) {  
         return mValues.get(i);  
     }  

     public long getItemId(int i) {  
         return i;  
     }  

     public View getView(int i, View view, ViewGroup viewGroup) {  
         View newView = null;  
         if(view != null) {  
             newView = view;  
         } else {  
             newView =(View)mInflater.inflate(R.layout.image_view, false);  
         }  

         Bitmap bitmap = BitmapFactory.decodeFile(mValues.get(i).fileName);  
         mBitmapRefs.add(new SoftReference(bitmap));     //此处加入ArrayList  
         ((ImageView)newView).setImageBitmap(bitmap);  

         return newView;  
     }  
}

2,解决Context引起的内存溢出:
在Android平台上,长期保持一些资源的引用,造成一些内存不能释放,带来的内存泄露问题很多。比如Context。
android中的很多资源文件都需要一个Context引用来加载,如果这些资源没有被释放,那么Context的引用不为null,造成对应的Activity即使 调用了finish()但其占有的内存依然不能被释放。这是 因为在Java或者Android内存机制中,顶点的结点释放前必须保证其他对象没有调用才能被系统GC回收释放。我们来看一段代码:

SoundManager.getInstance(this).play(SoundManger.MAIN_BG_SOUND);

从这段代码可以看出,声音管理类是一个单例,它对于整个应用进程来说是全局的,在进入应用的时候创建这个单利直到应用结束,这个单例才会被释放。大家可以看到这个类在得到单例的时候需要传递一个Context对象作为参数,因为要利用Context来加载声音资源。这就导致如果当前Activity调用了finish()全依然不能被GC,因为声音管理类是全局的,它持有了当前Activity的应用,阻止了其被GC。 解决的办法是尽量使用全局的Context来加载资源。修改如下:

SoundManager.getInstance(this.getApplicationContext).play(SoundManger.MAIN_BG_SOUND);

3,解决Thread 线程引起的内存溢出

如下代码:

private class MyThread extends Thread{

@Override

public void run() {

super.run();
while(bFlag)
{
//do somthing
}
}

MyThread mThread = new MyThread();

mThread.start();

这端代码 在主线程里新开了一个线程,并且在线程里循环处理一些逻辑。问题在于 如果控制线程结束的bFlag如果在Activity销毁时没有置为 false 将会产生很严重的后果。线程的一个特点是生命周期的不可控。如果Activity销毁时,没有结束线程的运行,那么不仅阻止了Activity被GC,而且大大降低了程序的性能。假如,再重新进入这个Activity,那么又创建了一个死循环的线程,而之前的那个线程依然在运行,这样程序就会非常的卡。所以 一定要注意,销毁Activity时一定要结束线程。

总而言之,想要避免context 相关的内存泄漏 ,记住以下几点:
a.不要对activity 的context 长期引用( 一个activity 的引用的生存周期应该和activity 的生命周期相同)
b.试着使用关于application的 context 来替代和activity相关的context
c.如果一个acitivity 的非静态内部类的生命周期不受控制,那么避免使用它;使用一个静态的内部类并且对其中的activity 使用一个弱引用。解决这个问题的方法是使用一个静态的内部类,并且对它的外部类有一WeakReference,就像在ViewRoot中内部类W所做的就是这么个例子。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>