王剛----メモリ最適化パフォーマンスの最適化(II)を最適化メモリメモリジッタと良いコーディングプラクティス

第一:ジッタメモリ
1、メモリ・ジッタの理由:(回収率は、分配速度より大きい場合)、頻繁なメモリ割り当てと回復、最終的にOOMを生成します。
(1)我々は、メモリ・ジッタ・コードを探し、二次元アレイ、頻出文字列の連結を開きます。

 public void imPrettySureSortingIsFree() {
        int dimension = 300;
        int[][] lotsOfInts = new int[dimension][dimension];
        Random randomGenerator = new Random();
        for (int i = 0; i < lotsOfInts.length; i++) {
            for (int j = 0; j < lotsOfInts[i].length; j++) {
                lotsOfInts[i][j] = randomGenerator.nextInt();
            }
        }

        for (int i = 0; i < lotsOfInts.length; i++) {
            String rowAsStr = "";
            //排序
            int[] sorted = getSorted(lotsOfInts[i]);
            //拼接打印
            for (int j = 0; j < lotsOfInts[i].length; j++) {
                rowAsStr += sorted[j];
                if (j < (lotsOfInts[i].length - 1)) {
                    rowAsStr += ", ";
                }
            }
            Log.i("ricky", "Row " + i + ": " + rowAsStr);
        }
    }
    

ときに文字列の連結は、操作のクローンを作成します。クローンは、オブジェクトのメモリブロックを作成していきます。

 public int[] getSorted(int[] input){
            int[] clone = input.clone();
            Arrays.sort(clone);
            return clone;
        }

プロファイルの実行]をクリックし、今回は主に割り当ておよび割り当て解除(一定期間回復メモリの数)は、2つのフィールド(メモリオブジェクトの数を開くために一定の期間)を参照してください。
プロファイルを実行するには、GC(ガベージコレクションの画像)アイコンが表示されます頻繁に表示されます。
回避策:使用のStringBufferのStringBuilder
メモリジッタ(2)WebViewが原因

 WebView webView = (WebView) findViewById(R.id.webview);
        webView.getSettings().setUseWideViewPort(true);
        webView.getSettings().setLoadWithOverviewMode(true);
        webView.loadUrl("file:///android_asset/shiver_me_timbers.gif");

ソリューション:独立プロセスを回します。現在の活動を実行している別のプロセスを開きます。ファイルの一覧では、プロセスIDを追加し、活動を見つけます。

 <activity android:name=".CachingActivity" android:process=":P"/>

勧告書かれたのWebViewの活動は、別のプロセスを開きます。私たちは、理由が理由のWebViewで、QQマイクロ手紙Jingdongはを開いて、あなたは彼らがプロセスの多くを持っています。

2は、コレクションアルゴリズム:
サブバンドの携帯電話のアルゴリズム
II:良いコーディング習慣は、メモリ最適化
1、データ型を基本データ型を使用しないでくださいは、需要より多くのスペースを占めています。例えば、使用intは10進数の整数を使用することができない、長く使用しないでください。
2、限り少ないイテレータ、foreachループとなるべく、自動包装の使用最小化
プロセスのソリューション3.データ構造及びアルゴリズムを、
(1)再帰アルゴリズムにforループ
(2)千内のHashMapの使用、データの量を最小限に抑えます疎アレイは、(キーは整数である)を使用ArrayMap(キーオブジェクト)が、HashMapのよりメモリ性能を節約することができます。スペースのための時間。
スパース整数をキーとして、梱包の問題はありません。オブジェクトのキーをArrayMap。
4列挙の最適化:
これは、列挙コードです

public enum SHAPE{
    RECTANGLE,
    TRIANGLE,
    SQUARE,
    CIRCLE
}

四つの値がありますが、それは、メモリ内の4つのオブジェクトを開きます。消費は、メモリのための比較的大きい
修正されます

package com.example.wuyang.lsn4code;

import android.support.annotation.IntDef;
import android.support.annotation.StringDef;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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;

    //flag的真和假表示将来取的数据可以用或(|)来输入;比如这种形式RECTANGLE|TRIANGLE
	//value表示可选值,只允许我们定义的四个值
    @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;
    }
}

これは、上のオブジェクトを開きます。
MainActivityでの使用に

 SHAPE s=new SHAPE();
 //因为flag=true,所以这里可以输入两个值
       s.setShape(SHAPE.CIRCLE|SHAPE.RECTANGLE);
       System.out.println(s.getShape());

静的最終的に問題の5.static。
初期化するために、コンパイラclinitメソッドによって呼び出さ静的な
静的な最終作業を初期化する必要はありません、パッケージはDEXファイルに直接呼び出すことができ、クラスの初期化メモリには適用されません。したがって、基本データ型のメンバーは、完全な静的最終のように書くことができる
接続文字列6(+)プラスの使用を最小限に
7.繰り返しアプリケーションメモリの問題が
、このような再帰関数と同様の方法(1)複数の呼び出し、コールバック関数を新しいオブジェクト、実行し
、新たなストリームオブジェクトに直接(2)読み出しサイクルを。メモリジッタを引き起こす可能性が高い新しいオブジェクトを再利用しないでください。
(3)しないでくださいonMeause()onLayout()onDraw( )の呼び出し自体が生じ、(例えばrequestLayout、無効化など)UIを更新します。
8.再利用するために、将来的に回復するGCを避ける
ようにListViewコントロールの最適化として、これです。
解決策:メモリーデザインモードのオブジェクトプール+ LRUアルゴリズムでは、
我々は、オブジェクトプール、一定のリユース何かを書くためにここにいます。ここでは、私は、プールオブジェクトする必要がある場合は、このクラスをオーバーライドすることができ、読者の後、クラスを記述します。

	/**
	 *首先,在freePool中我们初始化2(initialCapacity)个对象,这时候来了个用户,需要用我对象池中的对象。
	 *就在freePool中申请一个对象,并且把这个申请到的对象放到lentPool中,这时候用户使用
	 *的,就是lentPool中的这个对象。第二个用户来用,就重复第一个用户的操作。接下来来第三个
	 *用户的时候,发现freePool中已经没有能用的对象,如果来的用户申请的对象不大于最大值(maxCapacity),
	 *就允许freePool在开一个对象给用户使用。如果lentPool中的对象(用户申请的在使用的对象)已经达到了
	 *最大值,那么该用户就拿不到对象,只能等其它用户释放后才能使用。联想数据库的连接池。recyclerView就是
	 *用的这个原理。
	 */
package com.example.wuyang.lsn4code;

import android.util.SparseArray;
//这里可以存放任何对象,我们用泛型
public abstract class ObjectPool<T> {
    //空闲沲,用户从这个里面拿对象
	//对象池保存的东西不多,所以使用SparseArray,不使用HashMap,为了节省内存。
	//freePool表示能用的对象池
    private SparseArray<T> freePool;
    //lentPool表示正在使用对象池,用户正在使用的对象放在这个沲记录
    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){
					//我们就把找到的对象放到另外一个(lentPool)池里
                    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);
    }

}

私たちは、独自のオブジェクト・プールを作成します

package com.example.wuyang.lsn4code;

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();
    }
}

でMainActivityを使用する方法を見て。

 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("jett",o1.hashCode()+"");
        Log.i("jett",o2.hashCode()+"");
        Log.i("jett",o3.hashCode()+"");
        Log.i("jett",o4.hashCode()+"");
        Log.i("jett",o5.hashCode()+"");

ハッシュコードは、4つの異なる値をプリントアウト。
ここに画像を挿入説明
二点9、および関連オブジェクト活性が静的書かれていない。
内部クラスが定義され、9サードなど、以下のように

private class MyAsyncTask2 extends AsyncTask{
}

ソリューションは、弱い参照を使用して、このクラスは別ファイルとして書かれています

  private class MyAsyncTask2 extends AsyncTask{

        private WeakReference<Main2Activity> main2Activity;

        public MyAsyncTask2(Main2Activity main2Activity){
            this.main2Activity=new WeakReference<>(main2Activity);
        }

        @Override
        protected Object doInBackground(Object[] objects) {
            return doSomeing();
        }

        private Object doSomeing() {
            //做了很多事后
            return new Object();
        }
    }

第四の点9
我々は次のように、シングルモードの実施形態は、コールバック機能を備え書きます

package com.example.administrator.lsn6_demo;

import android.view.View;
import android.widget.Button;

import java.lang.ref.WeakReference;

public class Singleton {
    private static Singleton singleton;
    private Callback callback;
    public static Singleton getInstance(){
        if(singleton==null){
            singleton=new Singleton();
        }
        return singleton;
    }



    public void setCallback(Callback callback){
        this.callback=callback;
    }
    public Callback getCallback(){
        return callback;
    }
    public interface Callback{
        void callback();
    }

}

MainActivityコール

//这里使用了匿名内部类,会造成内存泄漏
  Singleton.getInstance().setCallback(new Singleton.Callback() {
            @Override
            public void callback() {
           //这里已经持有Activity的引用
           //单例是永不释放的东西,单例在 apk进程中是不会释放的,当然如果单例所属的进程没有了 
           // 单例也会被释放的

            }
        });

    }

以下にシングルトン

package com.example.administrator.lsn6_demo;

import android.view.View;
import android.widget.Button;

import java.lang.ref.WeakReference;

public class Singleton {
    private static Singleton singleton;
//    private Callback callback;
    private WeakReference<Callback> callback;
    public static Singleton getInstance(){
        if(singleton==null){
            singleton=new Singleton();
        }
        return singleton;
    }



    public void setCallback(Callback callback){
        this.callback=new WeakReference<>(callback);
    }
    public Callback getCallback(){
        return callback.get();
    }
    public interface Callback{
        void callback();
    }

}

9問題のハンドラ第五点は、二つの場所があることに留意すべき
最初の場所に注意する:
コードハンドラの1行を参照してください

 Handler handler=new Handler(Looper.myLooper());
 handler.sendMessage(new Message());

ループアプリケーションのライフサイクルが同じで、プログラム全体が終了していない、ハンドラも解除することはできません、対応する活動につながった、解放したことがありません。
ソリューション、弱い参照シングルライト級+


class MyHandler extends Handler{
    private WeakReference m;
    public MyHandler(Main2Activity activity){
        m=new WeakReference(activity);
    }
    }

注意すべき第二位

  m.post(new Runnable() {
           @Override
          public void run() {

           }
       }
       );

これは、非静的な内部クラスの漏れの問題です。ソリューション、別のクラスを作成します。
いずれの場合も、当社は、このような方法で、onDestroy()です。

 @Override
    protected void onDestroy() {
        super.onDestroy();
        //清楚所有的回调和消息
        handler.removeCallbacksAndMessages(null);
    }
}

おすすめ

転載: blog.csdn.net/qczg_wxg/article/details/89815974