美文网首页
浅谈性能优化-内存优化一

浅谈性能优化-内存优化一

作者: 大苏打6815 | 来源:发表于2019-10-28 15:16 被阅读0次
    内存抖动

    内存频繁的分配与回收,(分配速度大于回收的速度时)最终会产生OOM。

    image.png

    一个线程开辟如上图所示,蓝色部分是虚拟机运行的,你没办法去改虚拟机,只能从黄色部分入手,黄色部分就是你工程里面的一些引用,创建对象所执行的方法。

    大多数的OOM都是发生在左图,我们应该是按照左图去执行想办法解决。

    示例:
    如果我们不断的在内存中去创建对象,比如bitmap吧,是会内存泄漏的,我们可以去定义一个对象池。话不多说,上代码。如果bitmap不回收,业务需求是开始就创建两个对象,最多允许创建4个对象,当创建第五个对象时候发现还没回收我们就抛异常。

    首先我们创建一个ObjectPool类

    public abstract class ObjectPool<T> {
        //空闲沲,用户从这个里面拿对象
        private SparseArray<T> freePool;
        //正在使用沲,用户正在使用的对象放在这个沲记录
        private SparseArray<T> lentPool;
    
        //沲的最大值
        private int maxCapacity;
    
        public ObjectPool(int initialCapacity, int maxCapacity) {
            //初始化对象沲
            initalize(initialCapacity);
            this.maxCapacity=maxCapacity;
        }
    
        private void initalize(int initialCapacity) {
            lentPool=new SparseArray<>();
            freePool=new SparseArray<>();
            for(int i=0;i<initialCapacity;i++){
                freePool.put(i,create());
            }
        }
    
        /**
         * 申请对象
         * @return
         */
        public T acquire() throws Exception {
    
            T t=null;
            synchronized (freePool){
                int freeSize=freePool.size();
                for(int i=0;i<freeSize;i++){
                    int key=freePool.keyAt(i);
                    t=freePool.get(key);
                    if(t!=null){
                        this.lentPool.put(key,t);
                        this.freePool.remove(key);
                        return t;
                    }
                }
                //如果没对象可取了
                if(t==null && lentPool.size()+freeSize<maxCapacity){
                    //这里可以自己处理,超过大小
                    if(lentPool.size()+freeSize==maxCapacity){
                        throw new Exception();
                    }
                    t=create();
                    lentPool.put(lentPool.size()+freeSize,t);
    
    
                }
            }
            return t;
        }
    
        /**
         * 回收对象
         * @return
         */
        public void release(T t){
            if(t==null){
                return;
            }
            int key=lentPool.indexOfValue(t);
            //释放前可以把这个对象交给用户处理
            restore(t);
    
            this.freePool.put(key,t);
            this.lentPool.remove(key);
    
        }
    
        protected  void restore(T t){
        };
    
        protected abstract T create();
        public ObjectPool(int maxCapacity) {
            this(maxCapacity/2,maxCapacity);
        }
    
    }
    

    其次创建Myobject继承ObjectPool

    public class MyObjectPool extends ObjectPool{
        public MyObjectPool(int initialCapacity, int maxCapacity) {
            super(initialCapacity, maxCapacity);
        }
    
        public MyObjectPool(int maxCapacity) {
            super(maxCapacity);
        }
    
        @Override
        protected Object create() {//LRU
            return new Object();
        }
    }
    

    我们在Activity里面调用的时候这么写

     MyObjectPool pool=new MyObjectPool(2,4);
            Object o1=pool.acquire();
            Object o2=pool.acquire();
            Object o3=pool.acquire();
            Object o4=pool.acquire();
            Object o5=pool.acquire();
    
            Log.i("hello",o1.hashCode()+"");
            Log.i("hello",o2.hashCode()+"");
            Log.i("hello",o3.hashCode()+"");
            Log.i("hello",o4.hashCode()+"");
            Log.i("hello",o5.hashCode()+"");
    

    你会发现log打到4就不打了,第五个就会抛异常,这个异常我们自己想办法处理
    MyObject传参(2,4)是说开始的时候先在内存里面创建两个对象,最多允许创建4个,当创建第五个的时候,那么o1,o2直接可以拿内存里面现有的,创建o3,o4的时候,发现内存里面找不到这个对象的就会自动创建,因为最多创建四个嘛,有限定的,当创建第五个的时候就会报错,因为这个写法最多创建4个。这里的示例只是一种思想。防止内存溢出,内存抖动。

    枚举的优化

    我们开发过程中,很多地方需要用到枚举类型,不想让开发者更改我定义常量的属性值。
    其实我们有更好的办法优化
    比如我们有个叫SHAPE的类,里面四个属性,可以这些写

    public class SHAPE {
        public static final int RECTANGLE=0;
        public static final int TRIANGLE=1;
        public static final int SQUARE=2;
        public static final int CIRCLE=3;
    
    
        @IntDef(flag=true,value={RECTANGLE,TRIANGLE,SQUARE,CIRCLE})
        @Target({ElementType.PARAMETER,ElementType.METHOD,ElementType.FIELD})
        @Retention(RetentionPolicy.SOURCE)
        public @interface Model{
    
        }
    
        private @Model int value=RECTANGLE;
        public void setShape(@Model int value){
            this.value=value;
        }
        @Model
        public int getShape(){
            return this.value;
        }
    }
    

    然后在代码里面这样调用(关于注解可以去查查啊)

       SHAPE s=new SHAPE();
       s.setShape(SHAPE.CIRCLE|SHAPE.RECTANGLE);
       System.out.println(s.getShape());
    
    优化内存的娘号编码习惯

    1、循环尽量用foreach,少用iterrator,自动装箱少用
    2、数据结构的算法的解度处理。 数据量千级以内可以使用Sparse数组(key为整数),ArrayMap(key为对象) 性能不如HashMap但节约内存
    3、枚举的优化,上面讲到过,每一个枚举值都是一个单例对象,在使用它时会增加额外的内存消耗,所以枚举相比与 Integer 和 String 会占用更多的内存。较多的使用 Enum 会增加 DEX 文件的大小,会造成运行时更多的IO开销,使我们的应用需要更多的空间,特别是分dex多的大型APP,枚举的初始化很容易导致ANR。
    4、static会由编译器调用clinit方法进行初始化static final不需要进行初始化工作,打包在dex文件中可以直接调用,并不会在类初始化申请内存所以基本数据类型的成员,可以全写成static final。
    5、字符串的链接尽量少用(+)加号

    相关文章

      网友评论

          本文标题:浅谈性能优化-内存优化一

          本文链接:https://www.haomeiwen.com/subject/whwmnqtx.html