1

私のアプリは初回実行時に正常に動作します。その後、終了して再度実行すると、強制終了ウィンドウが表示されます。アプリを強制終了した後、再び正常に動作します。アプリは、強制終了と正常な動作を交互に繰り返します。

アプリが終了する前にクリーンアップが不足していますか?

以下は私のコードの一部です(foobar、actionview、actionthreadの3つのクラスが含まれています:

foob​​ar.java:

public class foobar extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(new ActionView(this));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }
}

public class ActionView extends SurfaceView implements SurfaceHolder.Callback {

    private ActionThread actionThread;

    public ActionView(Context context) 
    {
        super(context);
        getHolder().addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) 
    {
        actionThread = new ActionThread(holder,this);
        actionThread.setRunning(true);
        actionThread.start();
        }


    @Override
    public void surfaceDestroyed(SurfaceHolder holder) 
    {
        boolean retry = true;
        while(retry)
        {
            try
            {
                actionThread.join();
                retry=false;
            }
            catch(InterruptedException e)
            {
            }
        }
    }

    protected void displayGameState(Canvas canvas) 
    {
        //code...
        }

        public void updateGameState() 
    {
        //code.. 
         if something happens then
    actionThread.setRunning(false);
    ((Activity)getContext()).finish();

        }
}

ActionThread.java:

public class ActionThread extends Thread {

    private boolean threadIsRunning;
    private SurfaceHolder surfaceHolder;
    private ActionView actionView;
    private final static int MAX_FPS = 50;
    private final static int MAX_FRAME_SKIPS = 5;
    private final static int FRAME_PERIOD = 1000/MAX_FPS;
    private static final String TAG = ActionThread.class.getSimpleName();

    public ActionThread(SurfaceHolder holder, ActionView actionView) {
        this.actionView= actionView;
        surfaceHolder = holder;
    }

    public void setRunning(boolean running)
    {
        threadIsRunning = running;
    }

    @Override
    public void run() 
    {
        long tickCount = 0L;
        long totalFramesSkipped = 0L;
        Canvas canvas = null;
        long beginTime; //time the cycle began
        long timeDiff;  //time it took for cycle to execute
        int sleepTime; //milliseconds to sleep (< 0 if time it took to complete cycle is longer than FRAME_PERIOD
        int framesSkipped; //# of frames being skipped

        while(threadIsRunning)
        {
            tickCount++;
            try
            {
                canvas = surfaceHolder.lockCanvas();
                synchronized(surfaceHolder)
                {
                    beginTime = System.currentTimeMillis();
                    framesSkipped = 0;

                    actionView.updateGameState();
                    actionView.displayGameState(canvas);

                    //calc how long the cycle took
                    timeDiff = System.currentTimeMillis() - beginTime;
                    //calc sleep time
                    sleepTime = (int)(FRAME_PERIOD - timeDiff);

                    if(sleepTime > 0)
                    {
                        //if sleepTime > 0 , didn't fall behind. Try to sleep
                        try
                        {
                            Thread.sleep(sleepTime);
                        }
                        catch(InterruptedException e){}
                    }
                    while(sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS)
                    {   //fell behind and need to catch up (update without displaying)
                        actionView.updateGameState();
                        sleepTime+=FRAME_PERIOD; //add frame period to check if in next frame
                        framesSkipped++;
                        totalFramesSkipped++;
                    }
                }
            }
            finally
            {
                if(canvas != null)
                {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }

}

logcat エラーは次のとおりです。

05-03 22:47:45.449: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 36955K/38794K, paused 32ms
05-03 22:47:45.488: I/dalvikvm-heap(30596): Clamp target GC heap from 43.427MB to 42.000MB
05-03 22:47:45.488: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37165K/38794K, paused 18ms
05-03 22:47:45.535: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37165K/38794K, paused 29ms
05-03 22:47:45.574: I/dalvikvm-heap(30596): Clamp target GC heap from 43.674MB to 42.000MB
05-03 22:47:45.582: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37418K/38794K, paused 18ms
05-03 22:47:45.613: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37244K/38794K, paused 30ms
05-03 22:47:45.652: I/dalvikvm-heap(30596): Clamp target GC heap from 43.804MB to 42.000MB
05-03 22:47:45.652: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37551K/38794K, paused 17ms
05-03 22:47:45.684: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37551K/38794K, paused 27ms
05-03 22:47:45.699: E/dalvikvm-heap(30596): 258908-byte external allocation too large for this process.
05-03 22:47:45.723: I/dalvikvm-heap(30596): Clamp target GC heap from 43.804MB to 42.000MB
05-03 22:47:45.723: D/dalvikvm(30596): GC_FOR_MALLOC freed <1K, 43% free 3126K/5447K, external 37551K/38794K, paused 17ms
05-03 22:47:45.723: D/GraphicsJNI(30596): Waiting for heap walker to free more memory
05-03 22:47:45.723: D/GraphicsJNI(30596): Heap walker done, retry to allocate
05-03 22:47:45.754: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37298K/38794K, paused 27ms
05-03 22:47:45.793: I/dalvikvm-heap(30596): Clamp target GC heap from 43.804MB to 42.000MB
05-03 22:47:45.793: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37551K/38794K, paused 17ms
05-03 22:47:45.832: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37551K/38794K, paused 26ms
05-03 22:47:45.840: E/dalvikvm-heap(30596): 313968-byte external allocation too large for this process.
05-03 22:47:45.871: I/dalvikvm-heap(30596): Clamp target GC heap from 43.804MB to 42.000MB
05-03 22:47:45.871: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37551K/38794K, paused 17ms
05-03 22:47:45.871: D/GraphicsJNI(30596): Waiting for heap walker to free more memory
05-03 22:47:45.871: D/GraphicsJNI(30596): Heap walker done, retry to allocate
05-03 22:47:45.902: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37551K/38794K, paused 30ms
05-03 22:47:45.910: E/dalvikvm-heap(30596): 313968-byte external allocation too large for this process.
05-03 22:47:45.941: I/dalvikvm-heap(30596): Clamp target GC heap from 43.804MB to 42.000MB
05-03 22:47:45.941: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37551K/38794K, paused 17ms
05-03 22:47:45.941: E/GraphicsJNI(30596): VM won't let us allocate 313968 bytes
05-03 22:47:45.957: D/AndroidRuntime(30596): Shutting down VM
05-03 22:47:45.957: W/dalvikvm(30596): threadid=1: thread exiting with uncaught exception (group=0x4001e560)
05-03 22:47:45.965: E/AndroidRuntime(30596): FATAL EXCEPTION: main
05-03 22:47:45.965: E/AndroidRuntime(30596): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.graphics.Bitmap.nativeCreate(Native Method)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.graphics.Bitmap.createBitmap(Bitmap.java:507)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.graphics.Bitmap.createBitmap(Bitmap.java:474)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:379)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.somecomany.foobar.Element.Element.resizeBitmap(Element.java:48)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.somecomany.foobar.Element.Element.<init>(Element.java:31)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.somecomany.foobar.Element.MobileElement.<init>(MobileElement.java:24)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.somecomany.foobar.ActionView.surfaceCreated(ActionView.java:156)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.SurfaceView.updateWindow(SurfaceView.java:543)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.SurfaceView.dispatchDraw(SurfaceView.java:348)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.View.draw(View.java:6883)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.widget.FrameLayout.draw(FrameLayout.java:357)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.View.draw(View.java:6883)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.widget.FrameLayout.draw(FrameLayout.java:357)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2106)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewRoot.draw(ViewRoot.java:1562)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewRoot.performTraversals(ViewRoot.java:1298)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewRoot.handleMessage(ViewRoot.java:1911)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.os.Handler.dispatchMessage(Handler.java:99)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.os.Looper.loop(Looper.java:130)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.app.ActivityThread.main(ActivityThread.java:3821)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at java.lang.reflect.Method.invokeNative(Native Method)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at java.lang.reflect.Method.invoke(Method.java:507)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at dalvik.system.NativeStart.main(Native Method)
05-03 22:47:49.996: I/Process(30596): Sending signal. PID: 30596 SIG: 9
4

2 に答える 2

1

ログから、ビットマップの作成中にメモリ リークが発生しているように見えます。これは、アプリケーションが 2 回目に実行されたときに静的データ構造を介して、大きなサイズのオブジェクトがぶら下がっている場合に発生します。

もう 1 つのバリアント シナリオは、静的変数で Context または Activity を参照する場合です。これは基本的に、前の Activity がガベージ コレクションされるのを防ぎます。

これは、Android でアプリを「終了」しても、そのプロセスが必ずしも終了しないために発生します。そのため、再度実行すると、OS は時間のかかる手順をスキップでき、アプリをより速く起動できます。これは、すぐに再利用できるようにデータの一部を保持している場合には有効ですが、うっかり (巨大な) データの一部を保持しておいて、それらのデータを再作成しようとする場合には、非常に良くありません。

于 2012-05-04T03:50:02.683 に答える
0

アクティビティの LaunchMode を SingleTop に設定してみてください。

また、Activity onDestroy のときにリソースを解放する必要があります。幸運を。

于 2012-05-04T02:58:46.247 に答える