5

このメモリリークを特定しようとしています。

と の 2 つSurfaceViewsAありBます。を開始Aして に移動しB、[戻る] ボタンを押して に戻りA、もう一度 に移動しBます。

これを行うたびに割り当てられたメモリが増加し、最終的にはメモリ不足エラーが発生します。

これが、接続されたBの内部からに移動する方法ですSurfaceViewA

        Context context =  this.getContext();
        Intent i =new Intent(context, StartCareer.class);
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        context.startActivity(i);

どちらのビューにも、たくさんのビットマップが描画されています。ではB、 への参照が見つかりません。A私が考えることができる唯一のコンテキスト外の参照は、私が持っているグローバル クラスへの参照です。また、バックグラウンドでいくつかの分析が行われています。それは何百万もの異なるものになる可能性があると思います

Eclipse で DDMS ビューを表示していますが、何を見ているのか、または繰り返され続ける正確なオブジェクトを見つける方法がわかりません。

DDMS Allocation Tracker の短期集中コース/チュートリアル、または私が間違っていることを指摘してくれる人を受け入れます。


追加情報:

に描画されているビットマップがいくつかありSurfaceViewます。そのような例は次のBとおりです。

////At class level
Bitmap rightB,leftB;
////In the constructor
rightB = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.right), 100,75, true);
////In doDraw
canvas.drawBitmap(rightB, rbX, rbY, null);

そして私の onDestroys

@Override
public void surfaceDestroyed(SurfaceHolder holder) {


    if (mThread.isAlive()){
        mThread.setMenuRunning(false);
    }
}

そのため、MAT を実行したところ、少なくとも 1 つのリークが見つかりました。マイThreadキープが再作成されます。これが何をしているのかです。

@Override
public void surfaceCreated(SurfaceHolder holder) {
    loading=false;
    if (!mThread.isAlive()){
        mThread = new ViewThread(this);
        mThread.setMenuRunning(true);
        mThread.start();
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {

    if (mThread.isAlive()){ 
        mThread.setMenuRunning(false);
    }
}

ビューがフォーカスを失ったり取得したりするたびにこれらのメソッドが呼び出されると仮定すると、これは明らかに間違っているようです。そうならないようにこれを再編成するにはどうすればよいですか?

4

5 に答える 5

5

onDestroy()アプリ内およびアプリ内でこのメソッドを呼び出しonstop()ます。

private void unbindDrawables(View view) {
     Log.d(TAG,"in unbindDrawables");
        if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
            }
        ((ViewGroup) view).removeAllViews();
        view.setBackgroundResource(0);
        Log.d(TAG,"removed views");
        //finish();
        }
 }
于 2013-01-31T07:45:39.747 に答える
3

DDMS を使用してヒープ ダンプ (*.hprof ファイル) を作成します。「ヒープ有効化」の近くにあるボタン。

次に、*.hprof標準 SDK ツール " hprof-conv.exe"を使用して、このファイルを別のファイルに変換します。

次に、Eclipse メモリ アナライザー ツール ( http://www.eclipse.org/mat/ ) をダウンロードし (スタンドアロン ツールとしてダウンロードしました)、新しい を開き*.hprof fileますmemory leak analyzer。 bufferObjectManager が大きすぎて、全体のメモリの 50% 以上を占有しているとのことでした)。

きれいにすると(BufferObjectManager.getActiveInstance().unloadBufferObject(((RectangularShape) obj).getVertexBuffer());)少しは役に立ちますが、まだ問題があります。

このバッファを完全にクリアすると、テクスチャなどが失われます。問題がアプリを閉じるときのメモリ リークのみである場合、この問題を回避する方法は、onDestroy();このバッファをクリア ( ) することです。

于 2013-01-31T07:37:34.487 に答える
3

いくつかのヒント:

  • アクティビティの完了時にビットマップをリサイクルします (onDestroy など)。
  • 可能な限り、アクティビティ自体ではなくアプリケーション コンテキストをコンテキストとして使用する
于 2013-01-31T07:38:09.030 に答える
1

アクティビティの onDestroy() でビットマップを recycle() してみてください。

于 2013-01-31T07:37:13.617 に答える
0

あなたがする必要があることは、ここで詳しく説明されています。特定の問題については、これを行う必要があります

// resize to desired dimensions
    int height = b.getHeight();
    int width = b.getWidth();
    Log.d(TAG, "1th scale operation dimenions - width: " + width + ",
       height: " + height);

    double y = Math.sqrt(IMAGE_MAX_SIZE
            / (((double) width) / height));
    double x = (y / height) * width;

    Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x, 
       (int) y, true);
    b.recycle();
于 2013-01-31T07:51:49.743 に答える