关于安卓内存溢出问题探讨

对于安卓的内存溢出,我是找不到什么好的方法,曾经疯狂的百度过,看的文章都是大同小异,很多都是浮云,下面是我以前总结的,前些天有人问到,我自己也没解决,我翻到了自己的笔记,就是下面的,从word粘上来,大家探讨,看谁有其他解决方案可以交流下,下面是我的笔记:
大家都知道Android的上层应用是基于 Dalvik Virtual Machine的。Dalvik VM的特点是基于寄存器,相比SUN的JVM(基于堆栈,没有寄存器)来说,理论上完成同样的功能需要的指令条数少,但是指令集复杂。到了Android2.2,Dalvik终于实现了JIT(Just In Time)功能,前进了一大步。
近期
们遇到OutOfMemory的错误,通常是堆内存溢出。网上有些帖子说可以通过函数设置应用的HEAP SIZE:
    private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
    VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //
设置最小heap内存为6MB大小。

    用这个方法解决问题,其实是不对的。 

堆(HEAP)是VM中占用内存最多的部分,通常是动态分配的。堆的大小不是一成不变的,通常有一个分配机制来控制它的大小。比如初始的HEAP是4M大,当4M的空间被占用超过75%的时候,重新分配堆为8M大;当8M被占用超过75%,分配堆为16M大。倒过来,当16M的堆利用不足30%的时候,缩减它的大小为8M大。重新设置堆的大小,尤其是压缩,一般会涉及到内存的拷贝,所以变更堆的大小对效率有不良影响。

上面只是个例子,不过可以看到三个参数:max heap size, min heap size, heap utilization(堆利用率)。Max Heap Size,是堆内存的上限值,Android的缺省值是16M(某些机型是24M),对于普通应用这是不能改的。函数setMinimumHeapSize其实只是改变了堆的下限值,它可以防止过于频繁的堆内存分配,当设置最小堆内存大小超过上限值时仍然采用堆的上限值(16M),对于内存不足没什么作用。所以说堆内存的大小无法改变,也就无法阻止内存溢出,你通过VMRuntime.getRuntime()setMinimumHeapSize只是改变了堆的下限值而已,而且VMRuntime类在android
2.3系统及以上系统已经没有了。

经过我多次测试,设置利用率大小是启作用的,可是设置最小堆内存大小是不起作用的,而且通过getMinimumHeapSize方法获取的大小为0

setTargetHeapUtilization(float newTarget) 可以设定内存利用率的百分比,当实际的利用率偏离这个百分比的时候,虚拟机会在GC的时候调整堆内存大小,让实际占用率向个百分比靠拢。

     // 程序 onCreate 时调用  
    private final
    static floatTARGET_HEAP_UTILIZATION = 0.75f;

    VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);

经过我多次测试,用mVMRuntime.getTargetHeapUtilization()方法查看,程序本来的利用率就0.75f,所以这个设置不设置都一样。

因此上面的方法都没有用,网上非常多像上面方法的转载都是浮云


安卓内存的溢出主要是使用图片时的内存溢出 使用图片时怎样避免内存溢出呢?
问小华华的:
java.lang.Runtime这个类在安卓中还有用吗?它跟dalvik.system.VMRuntime类说的是同一个运行环境吗?
Runtime.getRuntime().totalMemory() freeMemory()/ 是否就是 Davik 虚拟机分配给 app 的大小和程序可用的内存大小 ?
答: android 下每个应用程序都会开启一个对应的 java 虚拟机   可以这样理解吧,对于内存图片导致的内存溢出确实没有什么好的解决办法,只能试着从降低图片的分辨率上去解决了 .

我的解决办法:
下面方法好像并没有损坏图片的质量。
通过下面的方法来设置
Activity的背景图片:

private Bitmap mBitmap;

       /**  设置背景图片  */
       private   void  setBackground() {
           mBitmap = BitmapUtil.readBitMap( this , R.drawable. top123_bg );
           rl_root .setBackgroundDrawable( new  BitmapDrawable( mBitmap ));  //rl_root 为根布局对象
       }  

   //Activity 中的大对象手动释放,主要有 ListView 、和 ListView 的适配器,和设置为背景图片的 bitmap
   @Override
   rotected   void  onDestroy() {
       leftListTurnPageUtil  =  rightGridTurnPageUtil  =  null ;
       listAdapter  =  null ;
       gridAdapter  =  null ;
       mGridView  =  null ;
       mListView  =  null ;
        if (! mBitmap .isRecycled()){
          mBitmap .recycle();  // 回收图片所占的内存
       }
       System.gc();  // 提醒系统及时回收
        super .onDestroy();
   }

public   class  BitmapUtil {
/**
以最省内存的方式读取本地资源的图片  
@param  context
@param  resId  图片资源 id
@return  Bitmap
*/
    public   static  Bitmap readBitMap(Context context,  int  resId){
       BitmapFactory.Options options =  new  BitmapFactory.Options();
       options. inPreferredConfig  = Bitmap.Config. RGB_565
       options. inPurgeable  =  true
       options. inInputShareable  =  true
       InputStream is = context.getResources().openRawResource(resId);  // 获取资源图片的输入流
        return  BitmapFactory. decodeStream (is, null , options); 
   }
}


解决方案参考自:
http://blog.csdn.net/dai_zhenliang  我在这里面转载了好几篇关于图片内存溢出的,有兴趣的可以看下,仅供参考,不一定能解决问题的,我的主要参考如下:
一、用
BitmapFactory.decodeStream方法来读取图片
尽量不要使用 setImageBitmap setImageResource BitmapFactory.decodeResource 来设置一张大图,因为这些函数在完成 decode 后,最终都是通过 java 层的 createBitmap 来完成的,需要消耗更多内存。因此,改用先通过 BitmapFactory.decodeStream 方法,创建出一个 bitmap ,再将其设为 ImageView source decodeStream 最大的秘密在于其直接调用 JNI>>nativeDecodeAsset() 来完成 decode ,无需再使用 java 层的 createBitmap ,从而节省了 java 层的空间。如果在读取时加上图片的 Config 参数,可以跟有效减少加载的内存,从而更有效阻止抛 out of Memory 异常。另外, decodeStream 直接拿的图片来读取字节码了,   不会根据机器的各种分辨率来自动适应,   使用了 decodeStream 之后,需要在 hdpi mdpi ldpi 中配置相应的图片资源,   否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。
二、以最省内存的方式读取本地资源的图片

public static Bitmap readBitMap(Context context, int resId){

            BitmapFactory.Options options =  new  BitmapFactory.Options();
            options. inPreferredConfig  = Bitmap.Config. RGB_565 ;
            options. inPurgeable  =  true ;
            options. inInputShareable  =  true ;
            InputStream is = context.getResources().openRawResource(resId);  // 获取资源图片的输入流
             return BitmapFactory. decodeStream(is, null , options);
       } 
三、以减少图片宽高的方式读取图片
1.  public   static  Bitmap readBitMap2(Context context,  int  resId) {
       InputStream is = context.getResources().openRawResource(resId);
       BitmapFactory.Options options =  new  BitmapFactory.Options();
       options. inJustDecodeBounds  =  false ;
       options. inSampleSize  = 10;  //width hight 设为原来的十分一
        return BitmapFactory. decodeStream(is, null ,options);
  }  
2. if(!bmp.isRecycle() ){
        bmp.recycle() //
回收图片所占的内存
        system.gc()//
提醒系统及时回收
    }

希望对大家有帮助,更希望有其他的解决方法的朋友们贡献一下自己的解决经验。

http://sunhuichuan.blog.163.com/blog/static/1849445962013316115224803/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值