Android Cache-メモリの基本原理とメカニズム管理


JAva言語がc/c++言語に比べて人間的な点はjavaに回収を専門に管理するゴミ回収器があることである.c/c++言語は「誰が作ったのか、誰が処理したのか」にすぎない.
GC
1,GCはごみ収集の意味(Gabage Collection)2,Javaが提供するGC機能は,対象が役割ドメインを超えてメモリを自動的に回収する目的を達成するかどうかを自動的に監視することができる.3 Java言語では、割り当てられたメモリを解放する表示操作方法が提供されていません.
ごみ回収の原理
ごみ回収器は通常、単独の低レベルのスレッドとして実行され、メモリスタック内で死亡したオブジェクトまたは長い間使用されていないオブジェクトを消去および回収することは予知できず、プログラマはリアルタイムでごみ回収器を呼び出してオブジェクトまたはすべてのオブジェクトをごみ回収することはできません.回収メカニズムには世代別複製ごみ回収と標識ごみ回収があり、増量ごみ回収
ごみ回収器の原理
GCの場合、プログラマがオブジェクトを作成すると、GCはそのオブジェクトのアドレス、サイズ、使用状況を監視し始めます.GCは、ヒープ内のすべてのオブジェクトを図面に記録および管理する.このようにして、どのオブジェクトが「到達可能」であり、どのオブジェクトが「到達不可能」であるかを決定します.GCは、いくつかのオブジェクトが「到達不可能」であると判断した場合、これらのメモリ領域を回収する責任があります.プログラマは手動でSystemを実行することができる.gc()は、GCの実行を通知しますが、Java言語仕様ではGCが必ず実行されるとは保証されていません.
AndroidでGCがメモリ漏れするのはどんな場合ですか?
Javaメモリ漏洩の根本的な原因は,再アクセス不可能な変数タイプの参照を保存することである.たとえば、静的メソッドはコンテキスト(context)を参照し、このcontextをグローバル変数に設定します.では、このcontextはメモリ漏れの「事件者」になります.
/** *        */
public class TestClass {

    private static Context mContext;

    //       ,     ,     。             
    public static void setContext(Context context) {
        mContext = context;
    }

    private void getContext() {
        Toast.makeText(mContext, "     ", Toast.LENGTH_LONG).show();
    }
}

Androidのメモリオーバーフローはどのように発生しますか?
Androidの仮想マシンはレジスタベースのDalvikで、その最大スタックサイズは一般的に16 Mで、あるマシンは24 Mです.
メモリ使用量が一定レベルを超えると、OOM(OutOfMemory)のエラーが発生します.
例:1,プログラムのミス,Contextなどのリソースの参照を長期にわたって保持する2,Bitmapなどの消費メモリが大きすぎるオブジェクトを複数保存する
一般的な状況は、資源が解放されないことです.メモリが大きすぎるオブジェクトは、メモリが制限を超えています.
メモリ管理
1.staticメンバー変数をstaticで修飾すると、その変数はクラスのインスタンスではなくクラスに属します.したがってstaticで修飾された変数は、ライフサイクルが長く、リソースの消費量が多すぎるインスタンスを参照するために慎重に使用されます(Contextの場合が最も多い).
もう一つ無視しやすい現象があります.
private static Drawable sBackground;    

   public void example (){  
        ImageView iv = new ImageView(this);  
        iv.setBackgroundDrawable(sBackground);  
   }  

コードのようにdrawableを静的に設定し、いつでもこのオブジェクトを呼び出すことができます.この静的オブジェクトがメモリ漏れを起こしたことは知らなかった.
Contexの参照は明示的に保存されていませんが、ImageviewはViewのサブクラスであるため、DrawableがViewに接続されるとDrawableはViewをコールバックに設定します:(ソースコード)
public class View implements Drawable.Callback /** * The application environment this view lives in. * This field should be made private, so it is hidden from the SDK. * {@hide} 
     */  
    protected Context mContext;

ViewにはContextの参照が含まれているため、実際にはContextの参照を保存しています.最終的なリファレンスチェーンは次のとおりです.Drawable->ImageView->Context
そのため、ContextはできるだけApplication Contextを使用します.ApplicationのContextのライフサイクルが長いからです.強い参照の代わりにWeakReferenceを使用します.たとえばWeakReference mContextReferenceを使用できます.
2,データベースカーソルデータベースに関するカーソルCursorは,データ量が小さいときに非常に容易に察知できない.しかし、データ量が大きい場合、メモリの問題が現れます.Cursorの値をparcelableを実装するクラスのメンバー変数に与え、応答する場所で値を取ることで、カーソルをタイムリーに閉じ、リソースを解放することができます.
3,スレッド
new Thread(new Runnable() {  
            public void run() {  
               // TODO do something 
           }  
        }).start(); 

スレッドを開くと、スレッドで時間のかかる操作が実行されます.このとき、このスレッドがまだ実行されている場合.縦画面切り替えが実行され、newはactivityを実行します.このとき、古いactivityのスレッドはまだ実行されているので、新しいactivityが実行されると、古いactivityは破棄されません.このように,このスレッドは内部クラスであるため,このactivityを参照し,runメソッドが終了しない限り,この古いactivityは破棄されず,メモリ漏れをもたらす.
また,非同期タスクAsyncTaskの問題はさらに深刻である.Threadはrun関数が終了しない場合にのみこのようなメモリリークの問題が発生するが,AsyncTask内部の実装メカニズムはThreadPoolExcutorを運用しており,このクラスで発生するThreadオブジェクトのライフサイクルは不確定であり,アプリケーションでは制御できないため,AsyncTaskがActivityの内部クラスであればメモリリークの問題が発生しやすい.
では、もしこのような状況に遭遇したら、どのように解決しますか?1,スレッドの内部クラスを,静的内部クラスに変更する.2,スレッド内部に弱いリファレンスを用いてContextリファレンスを保存する.
4,Bitmap
「スーパーデブ」、特に解像度の高い画像で、何枚も表示すると問題が顕著になります.
解決方法:1、直ちに廃棄する.Bitmapを使い切るときは、タイムリーにrecycleを落とします.recycleはすぐにBitmapを解放するとは確信していませんが、仮想マシンに「この画像は解放できる」というヒントを与えます.Bitmapオブジェクトを使用しない場合は、recycle()を呼び出してメモリを解放してからnullに設定する必要があります.recycle()ソースコードから見ると、呼び出しはBitmapのプライマリメモリをすぐに解放できるはずですが、テストの結果、すぐにメモリを解放できなかったことがわかります.2、サンプリングレートを設定します.縮小された画像を記載し、ユーザーが閲覧できるようにすればよい.Bitmapを使い切るときは、すぐにrecycleを落とします.3,ソフトリファレンス(SoftReference)を巧みに運用する.Bitmapを使用しても参照は保持されないため、Recycle関数を呼び出すことはできません.このときソフトリファレンスを巧みに活用することで,Bitmapをメモリ不足時に有効に解放することができる.
5,Adapterはlistviewやgridviewのアダプタについて最適化しないと結果が推定されます.重要なのは画像です.
private ArrayList<SoftReference<Bitmap>> mBitmaps = new ArrayList<SoftReference<Bitmap>>();

およびviewの多重化:ViewHolder.
6変数の役割ドメインを最小に設定します.1つの変数がメソッドレベルである場合、このメソッドの実行が完了すると、この変数は回収されます.この変数がクラスレベルである場合、ゴミ回収メカニズムは、クラスのすべての参照が除去されるまで回収されない必要があります.
したがって,変数の役割ドメインは実際の状況に応じて決まる.
7は、オブジェクトが本当に必要な場合にのみ、いくつかのオブジェクトが定義されたときに初期化される可能性があります.では、このオブジェクトを呼び出す前に問題が発生すると、そのオブジェクトが占めるメモリが無駄になります.したがって、本当にオブジェクトを使用する前に初期化する必要がある場合.
8、再循環で変数を定義しないでください.これはよくあるエラーです.
public void test() {
        for (int i = 0; i < 20; i++) {
            String name = "";
            name += i;
            Log.i("test", name);
        }
    }

これですべての名前を循環することができます.しかし、プログラムごとにString nameが作成されます.そして回収する.これにより、メモリの割り当てが追加され、ゴミ回収器の負担も増加します.
また、ループでStringは+を使用してリンクすると大きなオーバーヘッドになります.この場合、Stringは長いクエリーまたはtoStringを生成します.+でリンクすると、メモリのオーバーヘッドがどれほど大きいかがわかります.この場合、StringBufferなどの不変オブジェクトを使用して文字列のリンクを行います.
オブジェクトを再参照する場合はnullに設定します.これにより、メモリはすぐにメモリを解放できます.
9.finallyブロックtry/catchメソッドを使用すると、successまたはfinalにかかわらずfinallyメソッドが呼び出されます.メモリをクリーンアップする文をfinallyに配置して、メモリがクリーンアップされることを保証できます.
10,分散オブジェクト作成と削除の時間セットに大量のオブジェクトを作成し,特に大きなオブジェクトの場合は大量のメモリを必要とする.GCはこの時点でメモリと正合メモリの破片を回収します.このときは,主GCの頻度が増加し,次の新規オブジェクトの作成時に主GCを強制する機会が大幅に増加する.
はい、これがandroidメモリの基本的な知識です.プログラミングでこれらの問題に気づいたら、プログラムは大幅に最適化され、メンテナンスが容易になります.プロジェクトの最適化はフレームワークから論理へのプロセスだとは思わないでください.実際には、これらの小さな細部から出発することが多いです.