Android性能优化之内存优化

一、概述

在前面一篇博客整理了Android性能优化之内存优化,这篇就整理整理内存优化方面的知识

1.简介

RAM(random access memory)随机存取存储器。分为下面5种

  • 寄存器存储:速度最快。因为寄存器位于处理器内部,我们程序无法控制。
  • 栈(stack):存放的是基本数据类型(注意String不是基本数据类型)和引用。对象本身不存储在栈中,而是存储在堆中。
  • 堆(Heap):存放的是new产生的对象。在堆中的内存,由Java虚拟机自动回收。
  • 静态域:静态域中存放的是程序运行时一直存在的数据,如由static修饰的变量。
  • 常量池:常量池中除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值还包含一些以文本形式出现的符号引用。

2.常量池

###1.概念:
java中的常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个)。这个可以和线程池相似。其实说白了常量池也是一个内存空间。但是和new创建出来的空间不一样。下面通过代码演示两者的区别
###2.代码演示

public static void main(String[] args) {
        Integer a1 = new Integer(127) ;
        Integer a2 = new Integer(127) ;
        System.out.println(a1==a2); //false 

        Integer a3 = Integer.valueOf(127) ;
        Integer a4 = Integer.valueOf(127) ;
        System.out.println(a3 == a4); //true

        System.out.println(a1 == a3 ); //false

        Integer a5 = Integer.valueOf(128) ;
        Integer a6 = Integer.valueOf(128) ;
        System.out.println(a5 == a6); //false
    }

由上述的代码可知:每次new的都是一个新的空间,而第二个方式为什么返回true呢?这是因为大部分的基本数据类型都实现了常量池技术。这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种double、float则没有实现。而且 Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,另外注意一点:String也实现了线程线程池技术。

2.分析Integer类型valueOf()方法

下面就Integer型的为什么127可以而128不可以,看源码:

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

那low和high是什么呢?

 static final int low = -128;
 static final int high;
static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

看了上面的源码是不是明白了如果不是在-128到127之间,则会重新new的。

栈和堆的比较

  • 栈:存取速度比堆要快,仅次于寄存器。当定义一个变量时,(注意:这里不是申明,申明一个变量是不会分配内存的)。Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
  • 堆:存取速度较慢。当堆中的new产生数组和对象超出其作用域后,它们不会被释放,只有在没有引用变量指向它们的时候才变成垃圾,不能再被使用。即使这样,所占内存也不会立即释放,而是等待被垃圾回收器gc收走。这也是Java比较占内存的原因。
 int a = 1;
 int b = 1 ;

分析:
编译器先处理int a = 1;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向1。接着处理int b =1;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向1。这样,就出现了a与b同时均指向3的情况。这时,如果再让a=2;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并让a指向1;如果已经有了,则直接将a指向这个地址。

二、OOM

1.为什么会出现OOM

oom(Out Of Memory)在我们写代码的时候肯定经常遇到,那么为什么会出现这种问题呢?

  • 有限的堆内存,一般默认是16M。
  • 运行在虚拟机之上
  • 支持后台多任务处理

2.Bitmap

图片是最容易造成oom的,尤其是在ListView中或者瀑布流中上下滑动,不断加载,程序很容易崩溃。

解决方案

使用BitmapFactory.Options设置inSampleSize, 这样做可以减少对系统资源的要求。比如

BitmapFactory.Options options = new  BitmapFactory.Options(); 
options.inJustDecodeBounds = true ;
options.inSampleSize = 3 ;

上面2行代码就设置缩略图为原来的图的1/9。

图片像素:

  • ALPHA_8:每个像素占用1byte内存
  • ARGB_4444:每个像素占用2byte内存
  • ARGB_8888:每个像素占用4byte内存
  • RGB_565:每个像素占用2byte内存

图片默认是ARGB_8888,由此可以看出占用的内存比较大,再对图片要求不高的话,我们可以使用ARGB_4444或者RGB_565。

回收:
在我们不需要用某张图片的时候,可以将其回收

// 先判断是否已经回收  
if(bitmap != null && !bitmap.isRecycled()){  
    // 回收并且置为null  
    bitmap.recycle();  
    bitmap = null;  
}  

4中引用类型

  • 强引用:基本不会被释放。
  • 软引用:SoftReference,对Bitmap来说,就是用SoftReference包装下Bitmap
  • 弱引用:WeakReference。
  • 虚引用:PhantomReference

不过现在已经不推荐用软(弱)应用了,推荐使用LruCache(最近最少使用),关于4种种引用的具体用法会在下篇和LruCache一起介绍。

三、使用static修饰的变量

    private static Context context ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        context = this ;
    }

上面会导致Activity无法销毁,因为静态变量引用了当前Activity。

四、属性动画造成的内存泄漏

属性动画中有一类无限循环的动画,如果没有在onDestory()方法停止,就会无限循环下去,并且Activity的view将会被动画持有。而view又持有了Activity,导致Activity无法销毁。

OK,这篇关于内存优化的就结束了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值