【问题标题】:Out of Memory error - possibly due to memory leak?内存不足错误 - 可能是由于内存泄漏?
【发布时间】:2016-01-25 22:20:24
【问题描述】:

所以我在使用 android 模拟器时遇到了我的代码问题。我得到了同样的错误:抛出 OutOfMemoryError“无法分配 4776816 字节分配,2473998 个空闲字节和 2MB 直到 OOM” 我有一种感觉这是由于内存泄漏,因为我为每个类中的每个类创建对象,我想它会导致某种循环错误。这在 Java 中是不允许的吗?任何帮助将不胜感激..

代码如下:

public class BoardActivity extends AppCompatActivity {

Move move = new Move();
Button buttons[] = new Button[16];

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

    move.newGame();


    buttons[0] = (Button)findViewById(R.id.button1);buttons[0].setOnClickListener(new Button.OnClickListener(){
        public void onClick(View v){
           move.makeMove(move.cups.get(0));
            updateButtons();
        }});
    buttons[1] = (Button)findViewById(R.id.button2);buttons[1].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            move.makeMove(move.cups.get(1));
            updateButtons();
        }
    });
    buttons[2] = (Button)findViewById(R.id.button3);buttons[2].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            move.makeMove(move.cups.get(2));
            updateButtons();
        }
    });
    buttons[3] = (Button)findViewById(R.id.button4);buttons[3].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            move.makeMove(move.cups.get(3));
            updateButtons();
        }
    });
    buttons[4] = (Button)findViewById(R.id.button5);buttons[4].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            move.makeMove(move.cups.get(4));
            updateButtons();
        }
    });
    buttons[5] = (Button)findViewById(R.id.button6);buttons[5].setOnClickListener(new Button.OnClickListener(){
        public void onClick(View v){
            move.makeMove(move.cups.get(5));
            updateButtons();
        }
    });
    buttons[6] = (Button)findViewById(R.id.button7);buttons[6].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            move.makeMove(move.cups.get(6));
            updateButtons();
        }
    });
    buttons[7] = (Button)findViewById(R.id.button8);buttons[7].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            updateButtons();
        }
    });
    buttons[8] = (Button)findViewById(R.id.button9);buttons[8].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            move.makeMove(move.cups.get(8));
            updateButtons();
        }
    });
    buttons[9] = (Button)findViewById(R.id.button10);buttons[9].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            move.makeMove(move.cups.get(9));
            updateButtons();
        }
    });
    buttons[10] = (Button)findViewById(R.id.button11);buttons[10].setOnClickListener(new Button.OnClickListener(){
        public void onClick(View v){
            move.makeMove(move.cups.get(10));
            updateButtons();
        }
    });
    buttons[11] = (Button)findViewById(R.id.button12);buttons[11].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            move.makeMove(move.cups.get(11));
            updateButtons();
        }
    });
    buttons[12] = (Button)findViewById(R.id.button13);buttons[12].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
             move.makeMove(move.cups.get(12));
            updateButtons();
        }
    });
    buttons[13] = (Button)findViewById(R.id.button14);buttons[13].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            move.makeMove(move.cups.get(13));
            updateButtons();
        }
    });
    buttons[14] = (Button)findViewById(R.id.button15);buttons[14].setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            move.makeMove(move.cups.get(14));
            updateButtons();
        }
    });
    // Still have bug with this button - needs to be sorted
    buttons[15] = (Button)findViewById(R.id.button16);buttons[15].setOnClickListener(new Button.OnClickListener(){
        public void onClick(View v){
            updateButtons();
        }
    });

    updateButtons();
}


public void updateButtons(){
    for(int i=0; i<buttons.length; i++){
        buttons[i].setText(move.cups.get(i).toString());
    }
}
}

播放器类:

public class Player extends Move{

Random rand = new Random();
BoardActivity board = new BoardActivity();

/**public void setScoreCups(){
    if(returnCurrentPlayer()==1){
        oppositionScoreCup = cups.get(16);
        scoreCup = cups.get(8);
    }else{
        oppositionScoreCup = cups.get(8);
        scoreCup = cups.get(16);
    }
}**/
public void setNextPlayer(){
    if(returnCurrentPlayer()==1) {
        setTurnPlayer(2);
    }else if(returnCurrentPlayer()==2){
        setTurnPlayer(1);
    }
}
public int returnCurrentPlayer(){
    if(board.buttons[5].isEnabled()){
        return 1;
    }else{
        return 2;
    }
}
public void setRandomPlayer(){
    boolean b = rand.nextBoolean();
    if(b){
        setTurnPlayer(1);
    }else{
        setTurnPlayer(2);
    }
}

public void setTurnPlayer(int n){
    if(n==1) {
        for (int i = 1; i < 8; i++) {
            board.buttons[i].setEnabled(true);
        }
        for (int i = 9; i < 16; i++) {
            board.buttons[i].setEnabled(false);
        }
    }else if(n==2){
        for(int i=1; i<8; i++){
            board.buttons[i].setEnabled(false);
        }
        for(int i=9; i<16; i++){
            board.buttons[i].setEnabled(true);
        }
    }
}
public void setPlayer() {
    if ((move.currentCup.pebbleCount == 0) && (move.currentCup != move.scoreCup)) {
        Log.d("makeMove.java", "print cup index" + move.cups.indexOf(move.currentCup));
        //emptyCupSwitch(currentCup);
        move.currentCup.increasePebbleCount();
    }
    if (move.currentCup == move.scoreCup) {
        move.currentCup.increasePebbleCount();
        setTurnPlayer(move.currentPlayer);
    } else if (move.currentCup != move.scoreCup) {
        move.currentCup.increasePebbleCount();
        setNextPlayer();
    }
}


//needs to be changed



public static int score=0;

public void setScore(int n){

    score = n;
}

}

和移动类:

public class Move extends Game{

Player player = new Player();
public Cup oppositionScoreCup; public Cup scoreCup;
int i; int currentPlayer; int cupValue;
int currentIndex; int lastCupIndex = currentIndex + cupValue - 1;
Cup currentCup;

public List<Cup> cups;
public void newGame() {

    cups = new ArrayList<>();
    //Reset all cups
    for (int i = 0; i < 16; i++) {
        Cup cup = new Cup(7);
        cups.add(i, cup);
    }
}

//Returns the cup following the one entered in the parameters
public Cup getNextCup(Cup cup) {
    if (cups.indexOf(cup) == 15) {
        return cups.get(0);
    } else {
        return cups.get(cups.indexOf(cup) + 1);
    }
}


//Emptys current cup and switches pebbles to opposite side
public void emptyCupSwitch(Cup cup) {
    Cup oppCup;
    int index = cups.indexOf(cup);
    switch(index) {
        case 1:
            oppCup = cups.get(15);
            cups.get(1).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
            break;
        case 2:
            oppCup = cups.get(14);
            cups.get(2).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
            break;
        case 3:
            oppCup = cups.get(13);
            cups.get(3).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
            break;
        case 4:
            oppCup = cups.get(12);
            cups.get(4).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
        case 5:
            oppCup = cups.get(11);
            cups.get(5).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
        case 6:
            oppCup = cups.get(10);
            cups.get(6).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
        case 7:
            oppCup = cups.get(9);
            cups.get(7).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
        case 9:
            oppCup = cups.get(7);
            cups.get(9).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
        case 10:
            oppCup = cups.get(6);
            cups.get(10).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
        case 11:
            oppCup = cups.get(5);
            cups.get(11).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
        case 12:
            oppCup = cups.get(4);
            cups.get(12).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
        case 13:
            oppCup = cups.get(3);
            cups.get(13).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
        case 14:
            oppCup = cups.get(2);
            cups.get(7).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
        case 15:
            oppCup = cups.get(1);
            cups.get(7).pebbleCount += oppCup.pebbleCount;
            oppCup.emptyCup();
    }


}


//Method for Clicking Cup - Basic move - Skips oppositonScoreCup
public void makeMove(Cup cup) {
    cupValue = cup.returnPebbleCount();
    currentIndex = cups.indexOf(cup);
    currentCup = getNextCup(cup);
    cup.emptyCup();

    for (i = currentIndex; i < currentIndex + cupValue; i++) {

        if (i == lastCupIndex) {
           player.setPlayer();
        } else if (currentCup == oppositionScoreCup) {
            currentCup = getNextCup(currentCup);
        } else if (currentCup != oppositionScoreCup) {
            currentCup.increasePebbleCount();
            currentCup = getNextCup(currentCup);
        }
    }
    if(checkGameOver()){
        gameOver();
    }
}
}

【问题讨论】:

  • 哪一行导致了这个错误?
  • 您正试图在一个请求中分配 ~4MB 的内存。那是一个相当大的内存块。 Android's heap can get fragmented,不管任何真正的内存泄漏。我会专注于尝试不分配这样的大块,除非在进程启动时,根据需要重用块。或者,首先尝试弄清楚如何避免需要大块内存。
  • 我还注意到,在 3 个案例之后,您似乎放弃了 break。这是一个错误吗?
  • 我觉得你先设计有大问题。在父类(移动)中实例化和调用子(玩家)的方法。有什么理由吗?

标签: java android memory memory-leaks out-of-memory


【解决方案1】:

您的内存不足,因为您的代码将递归运行并创建无限数量的 BoardActivityMovePlayer 对象。

怎么样?好吧,当BoardActivity类被初始化时,行

Move move = new Move();

将创建新的Move 对象。这反过来会导致该行的执行

Player player = new Player();

来自Move 类。这将生成一个新的 Player 对象,其中包含

BoardActivity board = new BoardActivity();

现在这将创建另一个BoardActivity 对象,这将带我们回到开始创建对象生成的无限循环。

简单地说,BoardActivity->Move-&gt;Player->BoardActivity->Move->Player....

我猜AppCompatActivity 是一个安卓活动。 Android 活动非常繁重,并且在初始化时会分配大量的堆内存。这基本上就是您如此快地耗尽内存的原因。

您不应该以这种方式创建活动。要么创建一个并从主要活动开始,要么使用AndroidManifest将其作为默认活动加载

另外,与其为每个按钮创建单独的OnClickListener,不如创建一个OnClickListener 并使用 if 语句检查按钮 ID 以确定单击了哪个按钮。

【讨论】:

  • 我认为这是问题所在,但感谢您的验证。也感谢按钮上的提示 - 让我的生活更轻松!
  • 如果我使用继承是一样的吗?即我扩展了类的功能而不是创建一个对象?
  • 很高兴为您提供帮助 :) 很抱歉,我不确定您的这个问题是什么意思。
猜你喜欢
  • 2019-11-02
  • 2013-07-23
  • 1970-01-01
  • 1970-01-01
  • 2020-06-27
  • 2018-03-23
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多