user3897004
user3897004

Reputation:

Out of Memory error - possibly due to memory leak?

So I'm having an issue with my code when using the android emulator. I get the same error: Throwing OutOfMemoryError "Failed to allocate a 4776816 byte allocation with 2473998 free bytes and 2MB until OOM" I have a feeling this is due to memory leak as I create objects for each class within each other class and I imagine it's causing some kind of loop error. Is this disallowed in Java? Any help would be much appreciated..

Here is the code:

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());
    }
}
}

Player class:

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;
}

}

And Move class:

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();
    }
}
}

Upvotes: 1

Views: 287

Answers (1)

Aj_
Aj_

Reputation: 502

You are running out of memory because your code will run recursively and create an infinite number of objects of BoardActivity, Move and Player.

How? Well, when the BoardActivity class is initialized, the line

Move move = new Move();

will create new Move object. This, in turn will result in the execution of the line

Player player = new Player();

from inside the Move class. This will spawn a new Player object which contains the line

BoardActivity board = new BoardActivity();

Now this will create another BoardActivity object and this takes us back to the beginning creating an endless cycle of object spawning.

Simply put, BoardActivity->Move->Player->BoardActivity->Move->Player....

I'm guessing the AppCompatActivity is an android activity. Android activities are pretty heavy and allocates some good amount of heap memory when initialized. This is basically why you are running out of memory so quickly.

You shouldn't be creating an activity this way. Either create one and start from the main activity or load it as the default activity using the AndroidManifest

Also instead of creating a separate OnClickListener for each button, it would be better to create a single OnClickListener and check button ids using if statements to determine which button was clicked.

Upvotes: 1

Related Questions