Throwing OutOfMemoryError“无法分配带有空闲字节的字节分配,直到OOM为止”

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Throwing OutOfMemoryError“无法分配带有空闲字节的字节分配,直到OOM为止”相关的知识,希望对你有一定的参考价值。

我正在尝试制作游戏应用。我有3个活动(简介,游戏/主要和游戏结束)。该游戏在第一次尝试到第三次尝试时都可以正常运行,但是在第四次尝试重试时(在游戏结束活动中有一个重试按钮将您带回到主要活动),我收到此错误:E / art:抛出OutOfMemoryError“无法分配具有7416608可用字节的27581052字节分配,直到OOM为止”

我已经尝试:1)调整我使用的图像/位图的大小;2)将图像放置在不同的可绘制文件夹中,例如xhdpi,xxxhdpi(以及它们之间的所有...);3)在清单中添加android:hardwareAccelerated="false"android:largeHeap="true";而且所有这些都给我买了更多的重试机会,但并没有解决问题(8至10次尝试后,应用程序会收到相同的错误消息)。

我也尝试过这些,因为我在此论坛的一些答案中找到了它们:4)在游戏结束或主要活动上实现ComponentCallbacks2 onTrimMemory(https://developer.android.com/topic/performance/memory.html);5)在游戏结束或主要活动中添加类似内容:

@Override
public void onDestroy() 
    super.onDestroy();
    Runtime.getRuntime().gc();      

而且这些在我的问题上根本没有改变...

这里是Logcat:

04-26 00:22:39.665 31000-31000/com.example.theflyingdactylgameapp I/Timeline: Timeline: Activity_launch_request time:22242888
04-26 00:22:39.755 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc sticky concurrent mark sweep GC freed 2897(97KB) AllocSpace objects, 0(0B) LOS objects, 5% free, 121MB/128MB, paused 548us total 6.523ms
04-26 00:22:39.775 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 137MB to 128MB
04-26 00:22:39.775 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc partial concurrent mark sweep GC freed 1719(109KB) AllocSpace objects, 0(0B) LOS objects, 5% free, 121MB/128MB, paused 394us total 13.719ms
04-26 00:22:39.795 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 136MB to 128MB
04-26 00:22:39.795 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc concurrent mark sweep GC freed 1089(84KB) AllocSpace objects, 0(0B) LOS objects, 5% free, 120MB/128MB, paused 473us total 21.972ms
04-26 00:22:39.795 31000-31000/com.example.theflyingdactylgameapp I/art: Forcing collection of SoftReferences for 26MB allocation
04-26 00:22:39.815 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 136MB to 128MB
04-26 00:22:39.815 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc concurrent mark sweep GC freed 12(384B) AllocSpace objects, 0(0B) LOS objects, 5% free, 120MB/128MB, paused 386us total 17.719ms
04-26 00:22:39.815 31000-31000/com.example.theflyingdactylgameapp E/art: Throwing OutOfMemoryError "Failed to allocate a 27581052 byte allocation with 7416672 free bytes and 7MB until OOM"
04-26 00:22:39.825 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 136MB to 128MB
04-26 00:22:39.825 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc partial concurrent mark sweep GC freed 6(192B) AllocSpace objects, 0(0B) LOS objects, 5% free, 120MB/128MB, paused 387us total 7.547ms
04-26 00:22:39.845 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 136MB to 128MB
04-26 00:22:39.845 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 5% free, 120MB/128MB, paused 368us total 17.285ms
04-26 00:22:39.845 31000-31000/com.example.theflyingdactylgameapp I/art: Forcing collection of SoftReferences for 26MB allocation
04-26 00:22:39.855 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 136MB to 128MB
04-26 00:22:39.855 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 5% free, 120MB/128MB, paused 551us total 17.798ms
04-26 00:22:39.855 31000-31000/com.example.theflyingdactylgameapp E/art: Throwing OutOfMemoryError "Failed to allocate a 27581052 byte allocation with 7416608 free bytes and 7MB until OOM"
04-26 00:22:39.855 31000-31000/com.example.theflyingdactylgameapp D/skia: --- allocation failed for scaled bitmap
04-26 00:22:39.855 31000-31000/com.example.theflyingdactylgameapp D/AndroidRuntime: Shutting down VM
04-26 00:22:39.865 31000-31000/com.example.theflyingdactylgameapp E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.theflyingdactylgameapp, PID: 31000
    java.lang.OutOfMemoryError: Failed to allocate a 27581052 byte allocation with 7416608 free bytes and 7MB until OOM
        at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
        at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
        at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:613)
        at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:446)
        at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:469)
        at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:501)
        at com.example.theflyingdactylgameapp.FlyingDactylView.<init>(FlyingDactylView.java:57)
        at com.example.theflyingdactylgameapp.MainActivity.onCreate(MainActivity.java:21)
        at android.app.Activity.performCreate(Activity.java:6041)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1109)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2283)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2392)
        at android.app.ActivityThread.access$800(ActivityThread.java:154)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1308)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5273)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
04-26 00:22:39.875 31000-31000/com.example.theflyingdactylgameapp I/Process: Sending signal. PID: 31000 SIG: 9

这是游戏结束活动:

package com.example.theflyingdactylgameapp;

import ...

public class GameOverActivity extends AppCompatActivity 


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game_over);

        int score = (int) getIntent().getExtras().get("POPOINTS");
        Button startGameAgain = findViewById(R.id.play_again_btn);
        TextView displayScore = findViewById(R.id.displayScore);
        TextView displayRecord = findViewById(R.id.displayRecord);


        //update record
        SharedPreferences settings =getSharedPreferences("RECORD", Context.MODE_PRIVATE);
        int record = settings.getInt("RECORD", 0);

        String score1;
        String record1;
        if (score > record) 
            record = score;
            record1 = Integer.toString(record);
            score1 = Integer.toString(score);
            displayScore.setText(String.format("POPOINTS = %s", score1));
            displayRecord.setText(String.format("*NEW RECORD* = %s", record1));


            SharedPreferences.Editor editor = settings.edit();
            editor.putInt("RECORD", record);
            editor.apply();
        
        else 
            record1 = Integer.toString(record);
            score1 = Integer.toString(score);
            displayScore.setText(String.format("POPOINTS = %s", score1));
            displayRecord.setText(String.format("record = %s", record1));
        


        startGameAgain.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                Intent mainIntent = new Intent (GameOverActivity.this, MainActivity.class);
                startActivity(mainIntent);
            
        );



    




这是主要活动:

package com.example.theflyingdactylgameapp;

import...

public class MainActivity extends AppCompatActivity 

    private FlyingDactylView gameView;
    private Handler handler = new Handler();
    private final static long Interval = 30;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

        gameView = new FlyingDactylView(this);
        setContentView(gameView);

        Timer timer = new Timer();
        timer.schedule(new TimerTask() 
            @Override
            public void run() 
                handler.post(new Runnable() 
                    @Override
                    public void run() 
                      gameView.invalidate();
                    
                );
            
        , 0, Interval);
    




这是主要活动使用的视图:

package com.example.theflyingdactylgameapp;

import ...
public class FlyingDactylView extends View 

    private Bitmap dactyl[] = new Bitmap[2];
    private int dactylX = 10;
    private int dactylY;
    private int dactylSpeed;

    private int canvasWidth, canvasHeight;

    private int popo0X, popo0Y, popo0Speed = 16;
    private int popo2X, popo2Y, popo2Speed = 18;
    private int popo1X, popo1Y, popo1Speed = 20;
    private Bitmap popo[] = new Bitmap[2];

    private int redX, redY, redSpeed = 24;
    private int red1X, red1Y, red1Speed = 27;
    private Bitmap redBall;

    private int score, lifeCounterOfDactyl;

    private boolean touch = false;

    private Bitmap backgroundImage;
    private Paint scorePaint = new Paint();
    private Bitmap life[] = new Bitmap[2];

    // creating sound
    private SoundPool soundPool;
    private int sound1, sound2, sound3;


    // criando objetos na tela
    public FlyingDactylView(Context context) 
        super(context);

        dactyl[0] = BitmapFactory.decodeResource(getResources(), R.drawable.dactyl1);
        dactyl[1] = BitmapFactory.decodeResource(getResources(), R.drawable.dactyl2);

        backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.background);

        popo[0] = BitmapFactory.decodeResource(getResources(), R.drawable.popo1);

        popo[1] = BitmapFactory.decodeResource(getResources(), R.drawable.popo2);

        redBall = BitmapFactory.decodeResource(getResources(), R.drawable.red_ball);

        scorePaint.setColor(Color.WHITE);
        scorePaint.setTextSize(70);
        scorePaint.setTypeface(Typeface.DEFAULT_BOLD);
        scorePaint.setAntiAlias(true);

        life[0] = BitmapFactory.decodeResource(getResources(), R.drawable.egg);
        life[1] = BitmapFactory.decodeResource(getResources(), R.drawable.broken_egg);

        dactylY = 550;
        score = 0;
        lifeCounterOfDactyl = 3;

        // creating sound player and placing sounds
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 
            AudioAttributes audioAttributes = new AudioAttributes.Builder()
                    .setUsage(AudioAttributes.USAGE_GAME)
                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .build();
            soundPool = new SoundPool.Builder()
                    .setMaxStreams(5)
                    .setAudioAttributes(audioAttributes)
                    .build();
        
        else 
            soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
        
        sound1 = soundPool.load(this.getContext(), R.raw.fly, 1);
        sound2 = soundPool.load(this.getContext(), R.raw.pick_popo, 1);
        sound3 = soundPool.load(this.getContext(), R.raw.red_hit, 1);




    
    // movimentos
    @Override
    protected void onDraw(Canvas canvas) 
        super.onDraw(canvas);

        canvasWidth = canvas.getWidth();
        canvasHeight = canvas.getHeight();

        canvas.drawBitmap(backgroundImage,0, 0, null);

        // movimentos dactyl
        int minDactylY = dactyl[0].getHeight();
        int maxDactylY = canvasHeight - dactyl[0].getHeight() * 3;
        dactylY += dactylSpeed;
        if (dactylY < minDactylY) 
            dactylY = minDactylY;
        
        if (dactylY > maxDactylY) 
            dactylY = maxDactylY;
        
        dactylSpeed += 2;

        if (touch) 
            canvas.drawBitmap(dactyl[1], dactylX, dactylY, null);
            touch = false;
        
        else 
            canvas.drawBitmap(dactyl[0], dactylX, dactylY, null);
        


        // movimentos popó
        popo0X -= popo0Speed;

        if (hitPopoChecker(popo0X, popo0Y)) 
            score += 10;
            popo0X = -100;
            // sound when hit popo0
            soundPool.play(sound2, 1, 1,0, 0, 1);
        

        if (popo0X < 0) 
            popo0X = canvasWidth + 21;
            popo0Y = (int) Math.floor(Math.random() * (maxDactylY - minDactylY)) + minDactylY;
        

        canvas.drawBitmap(popo[0], popo0X, popo0Y, null);



        // movimentos popó2
        popo2X -= popo2Speed;

        if (hitPopoChecker(popo2X, popo2Y)) 
            score += 10;
            popo2X = -100;
            // sound when hit popo2
            soundPool.play(sound2, 1, 1,0, 0, 1);
        

        if (popo2X < 0) 
            popo2X = canvasWidth + 21;
            popo2Y = (int) Math.floor(Math.random() * (maxDactylY - minDactylY)) + minDactylY;
        

        canvas.drawBitmap(popo[0], popo2X, popo2Y, null);


        // movimentos popó gordo
        popo1X -= popo1Speed;

        if (hitPopoChecker(popo1X, popo1Y)) 
            score += 20;
            popo1X = -100;
            // sound when hit popo gordo
            soundPool.play(sound2, 1, 1,0, 0, 1);
        

        if (popo1X < 0) 
            popo1X = canvasWidth + 21;
            popo1Y = (int) Math.floor(Math.random() * (maxDactylY - minDactylY)) + minDactylY;
        

        canvas.drawBitmap(popo[1], popo1X, popo1Y, null);


        // movimentos Red Ball
        redX -= redSpeed;

        if (hitPopoChecker(redX, redY)) 
            redX = -100;
            lifeCounterOfDactyl--;
            // sound when hit red ball 1
            soundPool.play(sound3, 1, 1,0, 0, 1);

            if (lifeCounterOfDactyl == 0) 
                Toast.makeText(getContext(), "Game Over", Toast.LENGTH_SHORT).show();

                Intent gameOverIntent = new Intent(getContext(), GameOverActivity.class);
                // free up resources from sound on Game Over by red ball 1
                soundPool.release();
                soundPool = null;

                gameOverIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                gameOverIntent.putExtra("POPOINTS", score);
                getContext().startActivity(gameOverIntent);
            
        

        if (redX < 0) 
            redX = canvasWidth + 21;
            redY = (int) Math.floor(Math.random() * (maxDactylY - minDactylY)) + minDactylY;
        

        canvas.drawBitmap(redBall, redX, redY, null);

        // movimentos Red Ball2
        red1X -= red1Speed;

        if (hitPopoChecker(red1X, red1Y)) 
            red1X = -100;
            lifeCounterOfDactyl--;
            // sound when hit red ball 1
            soundPool.play(sound3, 1, 1,0, 0, 1);

            if (lifeCounterOfDactyl == 0) 
                Toast.makeText(getContext(), "Game Over", Toast.LENGTH_SHORT).show();

                Intent gameOverIntent = new Intent(getContext(), GameOverActivity.class);
                // free up resources from sound on Game Over by red ball 2
                soundPool.release();
                soundPool = null;

                gameOverIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                gameOverIntent.putExtra("POPOINTS", score);
                getContext().startActivity(gameOverIntent);
            
        

        if (red1X < 0) 
            red1X = canvasWidth + 21;
            red1Y = (int) Math.floor(Math.random() * (maxDactylY - minDactylY)) + minDactylY;
        

        canvas.drawBitmap(redBall, red1X, red1Y, null);




        // Score
        canvas.drawText("Popoints: " + score, 20, 60, scorePaint);

        // life counter
        for (int i=0; i<3; i++) 
            int x = (int) (700 + life[0].getWidth() * 1.9 * i);
            int y = 10;

            if (i < lifeCounterOfDactyl) 
                canvas.drawBitmap(life[0], x, y, null);
            
            else 
                canvas.drawBitmap(life[1], x, y, null);
            
        



    

    public Boolean hitPopoChecker (int x, int y) 
        if (dactylX < x && x < (dactylX + dactyl[0].getWidth()) && dactylY < y && y < (dactylY + dactyl[0].getHeight())) 
            return true;
        
        return false;
    

    @Override
    public boolean onTouchEvent(MotionEvent event) 
        if (event.getAction() == MotionEvent.ACTION_DOWN) 
            touch = true;
            // decrease here to make Dactyl goes faster
            dactylSpeed = -22;
            // sound when tap to fly
            soundPool.play(sound1, 1, 1,0, 0, 1);
        
        return true;
    



非常感谢您提供任何有关尝试解决该问题的建议,谢谢!

答案

当您在MainActivity.onCreate中创建计时器任务时,它将保留对活动的引用。永远不会清除该引用,因为计时器线程永远不会停止,因此用于活动的内存永远不会被回收和重新使用。这称为内存泄漏。

您需要在活动中保留对计时器的引用,并在onDestroy中取消计时器。

以上是关于Throwing OutOfMemoryError“无法分配带有空闲字节的字节分配,直到OOM为止”的主要内容,如果未能解决你的问题,请参考以下文章

(HttpWebResponse)request.GetResponse() throwing 操作已经超时

UVA10759 Dice Throwing概率+DP

UVA10759 Dice Throwing概率+DP

Swift 60秒45 - Running throwing functions

Light OJ 1064 - Throwing Dice

UVA10940 Throwing cards away II数学规律+约瑟夫环