Android 加载图片时出错,内存溢出

Android里图片溢出,报错信息为以下内容:

java.lang.outofmemoryerror

Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M ,一般是8M。在真机上,应该远远不止这么小,具体多少我也不知道,有知道的请告诉我(我看资料有说真机使用第三方ROM,内存分配有40MB ),一般在虚拟机上会报内存溢出错的,实际上在真机上是不会报错的,这个我有实际体会。然后如果在虚拟机上报错了的,在真机上没报错,那么这个问题存在但可以先放着,但必须解决。一般在三星真机上不会出这个错,但在差一点的手机比如华为的某个机器上就报错了。

我的图片远没有8M,所有的图片加起来都没有这么大,但还是报了这个错,要想办法解决。

可以通过 long freeStart = Runtime.getRuntime().freeMemory(); 来查看内存

我先查了自己的资源,看是否有占用的资源没有释放。

资源释放问题:

转载JAVA之旅的Android防止内存溢出浅析(有改动,http://www.cnblogs.com/java-android/archive/2012/06/24/2560405.html )

Android平台上,长期保持一些资源的引用,造成一些内存不能释放,带来的内存泄露问题很多。比如:Context(下文中提到的Activity都是Context),在一些你需要保持你的首个类对象状态,并且把状态传入其他类对象中时,这样消除掉首个类对象之前,你必须先把接收类对象释放掉。需要注意一点的是:因为在Java或者Android内存机制中,顶点的结点释放前必须保证其他对象没有调用才能被系统GC回收释放。我们来看一段代码:

  

 @Override  

 protected void onCreate(Bundle state) {  

      super.onCreate(state);  

      TextViewlabel = new TextView(this);  

      label.setText("Leaksare bad");  

      setContentView(label);  

 }  

这个代码的意思就是我们把一个TextView的实例加载到了我们正在运行的ActivityContext)当中,因此,通过GC回收机制,我们知道,要释放Context,就必须先释放掉引用他的一些对象。如果没有,那在要释放Context的时候,你会发现会有大量的内存溢出。所以在你不小心的情况下内存溢出是一件非常容易的事情。 保存一些对象时,同时也会造成内存泄露。最简单的比如说位图(Bitmap),比如说:在屏幕旋转时,会破坏当前保持的一个Activity状态,并且重新申请生成新的Activity,直到新的Activity状态被保存。我们再看一段代码:  

 privatestatic 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);  

 }  

这个代码是非常快的同时也是错误的。它的内存泄露很容易出在屏幕转移的方向上。虽然我们会发现没有显示的保存Context这个实例,但是当我们把绘制的图连接到一个视图的时候,Drawable就会将被View设置为回调,这就说明,在上述的代码中,其实在绘制TextView到活动中的时候,我们已经引用到了这个Activity。链接情况可以表现为:Drawable->TextView->Context

所以在想要释放Context的时候,其实还是保存在内存中,并没有得到释放。

如何避免这种情况:主要在于。线程最容易出错。大家不要小看线程,在Android里面线程最容易造成内存泄露。线程产生内存泄露的主要原因在于线程生命周期的不可控。下面有一段代码:

  

publicclass MyTest extends Activity {  

     @Override  

     publicvoid onCreate(BundlesavedInstanceState) {  

         super.onCreate(savedInstanceState);  

         setContentView(R.layout.main);  

         new MyThread().start();  

     }  

    

     privateclass MyThread extends Thread{  

         @Override  

         public void run() {  

            super.run();  

            //do somthing  

         }  

     }  

}  

代码很简单,但是在Android上又来新问题了,当我们在切换视图屏幕的时候(横竖屏),就会重新建立横屏或者竖屏的Activity。我们形象的认为之前建立的Activity会被回收,但是事实如何呢?Java机制不会给你同样的感受,在我们释放Activity之前,因为run函数没有结束,这样MyThread并没有销毁,因此引用它的ActivityMytest)也有没有被销毁,因此也带来的内存泄露问题。

有些人喜欢用Android提供的AsyncTask,但事实上AsyncTask的问题更加严重,Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。

如果要使用到Context,尽量使用ApplicationContext去代替Context,因为ApplicationContext的生命周期较长,引用情况下不会造成内存泄露问题 

然后再就是图片处理问题。

第一可以自己设置堆内存: 

private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
    VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); 

堆内存一般有个上限值,一般为16M,有好的机型是24M,你设个高于此值的会按照上限值来算的。

第二可以处理图片

缩小图片大小,分辨率会下降,有可能失真

低内存编码

//以省内存的方式读取图片

public Bitmap getBitmap(InputStream is){

   BitmapFactory.Options opt = new BitmapFactory.Options();   

        opt.inPreferredConfig = Bitmap.Config.RGB_565; 

//下面两个要一起用   

       opt.inPurgeable = true;   

       opt.inInputShareable = true; 

       opt.inSampleSize = 4;

          //获取资源图片   

       //InputStream is = mContext.getResources().openRawResource(resId);   

           return BitmapFactory.decodeStream(is,null,opt);   

}

//以省内存的方式读取图片

public Bitmap getBitmap(int resId){

   BitmapFactory.Options opt = new BitmapFactory.Options();   

        opt.inPreferredConfig = Bitmap.Config.RGB_565;    

       opt.inPurgeable = true;   

       opt.inInputShareable = true;   

       opt.inSampleSize = 4;

          //获取资源图片   

      // InputStream is = mContext.getResources().openRawResource(resId);   

           return BitmapFactory.decodeResource(mContext.getResources(), resId,opt);   

}

Android中有四种,分别是:
ALPHA_8:每个像素占用1byte内存
ARGB_4444:每个像素占用2byte内存
ARGB_8888:每个像素占用4byte内存
RGB_565:每个像素占用2byte内存
Android默认的颜色模式为ARGB_8888,这个颜色模式色彩最细腻,显示质量最高。但同样的,占用的内存也最大。
1 BitmapFactory.Options options = new BitmapFactory.Options();
2 options.inPreferredConfig = Bitmap.Config.ARGB_4444;    
3 Bitmap img = BitmapFactory.decodeFile("/sdcard/1.png", options); 
以上代码即是将1.png以ARGB_4444模式读出。内存减少虽然不如第一种方法明显,但是对于大多数图片,看不出与ARGB_8888模式有什么差别。不过在读取有渐变效果的图片时,可能有颜色条出现。另外,会影响图片的特效处理。

第三缓存进内存里,但要记得释放回收

释放

@Override

       public void releaseImage(String path) {

              if(mImageCache.containsKey(path)) {

                     SoftReference<Bitmap> reference = mImageCache.get(path);

                     Bitmap bitmap = reference.get();

                     if(null != bitmap) {

                            Log.d(“OomDemo”, “recyling ” + path);

                            bitmap.recycle();

                     }

                     mImageCache.remove(path);

              }

       }

已标记关键词 清除标记
相关推荐
程序员的必经之路! 【限时优惠】 现在下单,还享四重好礼: 1、教学课件免费下载 2、课程案例代码免费下载 3、专属VIP学员群免费答疑 4、下单还送800元编程大礼包 【超实用课程内容】  根据《2019-2020年中国开发者调查报告》显示,超83%的开发者都在使用MySQL数据库。使用量大同时,掌握MySQL早已是运维、DBA的必备技能,甚至部分IT开发岗位也要求对数据库使用和原理有深入的了解和掌握。 学习编程,你可能会犹豫选择 C++ 还是 Java;入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何, MySQL 都是 IT 从业人员不可或缺的技能!   套餐中一共包含2门MySQL数据库必学的核心课程(共98课时)   课程1:《MySQL数据库从入门到实战应用》   课程2:《高性能MySQL实战课》   【哪些人适合学习这门课程?】  1)平时只接触了语言基础,并未学习任何数据库知识的人;  2)对MySQL掌握程度薄弱的人,课程可以让你更好发挥MySQL最佳性能; 3)想修炼更好的MySQL内功,工作中遇到高并发场景可以游刃有余; 4)被面试官打破沙锅问到底的问题问到怀疑人生的应聘者。 【课程主要讲哪些内容?】 课程一:《MySQL数据库从入门到实战应用》 主要从基础篇,SQL语言篇、MySQL进阶篇三个角度展开讲解,帮助大家更加高效的管理MySQL数据库。 课程二:《高性能MySQL实战课》主要从高可用篇、MySQL8.0新特性篇,性能优化篇,面试篇四个角度展开讲解,帮助大家发挥MySQL的最佳性能的优化方法,掌握如何处理海量业务数据和高并发请求 【你能收获到什么?】  1.基础再提高,针对MySQL核心知识点学透,用对; 2.能力再提高,日常工作中的代码换新貌,不怕问题; 3.面试再加分,巴不得面试官打破沙锅问到底,竞争力MAX。 【课程如何观看?】  1、登录CSDN学院 APP 在我的课程中进行学习; 2、移动端:CSDN 学院APP(注意不是CSDN APP哦)  本课程为录播课,课程永久有效观看时长 【资料开放】 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化。  下载方式:电脑登录课程观看页面,点击右侧课件,可进行课程资料的打包下载。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页