2017-02-14 2 views
-3

Je travaille sur un projet qui essaie d'utiliser un réseau de neurones pour apprendre à jouer à un jeu de dames. Pendant l'entraînement de mon réseau, je dois faire des simulations de nombreux jeux (plus de 10000 jeux). Lors de la vérification de la mémoire du tas à l'aide de la visionneuse de mémoire d'Intellij, tout semble normal. Chaque objet CheckerGame et les champs qui lui sont associés (CheckerPieces, GameBoard, etc.) semblent finalement être recyclés par le garbage collector de Java. Cela signifie qu'une fois qu'un jeu de dames est terminé, les ressources du jeu sont correctement éliminées. Après avoir exécuté le programme d'entraînement un peu plus longtemps, il semble que le garbage collector de Java décide d'arrêter de recycler mes objets de jeu, puis j'obtiens finalement une erreur OutOfMemoryError au fur et à mesure que les objets du jeu s'accumulent. Voici un exemple de ce dont je parle memory leak.Le programme Java démarre bien, mais entraîne une fuite de mémoire

Il y a évidemment une fuite de mémoire mais cela n'a aucun sens, car le programme recycle correctement les ressources du jeu la plupart du temps.

EDIT: Code

public class CheckersGame { 
private GameBoard board; 
private Player redPlayer; 
private Player bluePlayer; 

private boolean isBlueTurn; 

private int winner = -2; 
private int redGamesWon = 0; 
private int blueGamesWon = 0; 

private int turnNumber = 0; 
private int blueTurnNumber = 0; 

public boolean gameover = false; 

public CheckersGame() { 

} 

public void initializeGame() { 
    winner = -2; 
    redGamesWon = 0; 
    blueGamesWon = 0; 
    turnNumber = 0; 
    blueTurnNumber = 0; 

    redPlayer = new RedPlayer(); 
    bluePlayer = new BluePlayer(); 
    board = new GameBoard(redPlayer, bluePlayer); 
    redPlayer.setBoard(board); 
    bluePlayer.setBoard(board); 

    isBlueTurn = false; 
    board.setUpGameBoard(); 
} 

public void turn() { 
    Random rng = new Random(); 
    try { 
     LegalMove[] possibleMovesRed = redPlayer.getAllPossibleValidMoves(); 
     LegalMove[] possibleMovesBlue = bluePlayer.getAllPossibleValidMoves(); 

     if (turnNumber == 150) { 
      winner = 0; 
      System.out.println("Tie " + NeuralNet.testint + "/" + NeuralNet.otherint + " | " + blueTurnNumber); 
      NeuralNet.testint = 0; 
      NeuralNet.otherint = 0; 
     } 
     if (board.whoWon(possibleMovesBlue, possibleMovesRed) == redPlayer) { 
      winner = -1; 
      System.out.println("Red Won " + NeuralNet.testint + "/" + NeuralNet.otherint + " | " + blueTurnNumber); 
      NeuralNet.testint = 0; 
      NeuralNet.otherint = 0; 
      redGamesWon++; 
     } else if (board.whoWon(possibleMovesBlue, possibleMovesRed) == bluePlayer) { 
      winner = 1; 
      System.out.println("Blue Won " + NeuralNet.testint + "/" + NeuralNet.otherint + " | " + blueTurnNumber); 
      NeuralNet.testint = 0; 
      NeuralNet.otherint = 0; 
      blueGamesWon++; 
     } else { 
      if (isBlueTurn) { //Blue turn (NN) 
       LegalMove nextMove = NeuralNet.getMoveNN(bluePlayer.getNetwork(), bluePlayer.convertBoard(), possibleMovesBlue, bluePlayer); 
       bluePlayer.movePiece(nextMove); 
       isBlueTurn = false; 
       blueTurnNumber++; 
      } else { // Red's turn (random) 

       int upperBound = possibleMovesRed.length; 
       LegalMove randomMove = possibleMovesRed[(rng.nextInt(upperBound))]; 
       redPlayer.movePiece(randomMove); // executes random move 
       isBlueTurn = true; 
      } 


      // gc 
      for (LegalMove move : possibleMovesBlue) { 
       move.clearTree(); 
      } 

      for (LegalMove move : possibleMovesRed) { 
       move.clearTree(); 
      } 

      possibleMovesBlue = null; 
      possibleMovesRed = null; 
      turnNumber++; 
     } 
    } catch (InvalidMoveException ime) { 
     ime.printCustomError(); 
    } 
} 

}

Code de formation (scorePlayer est constamment appelé et les résultats du jeu est retourné au réseau de neurones):

public class NeuralPlayerRandom { 
private NEATNetwork network; 
private static int playerIteration = 1; 

public NeuralPlayerRandom(NEATNetwork network) { 
    this.network = network; 
} 


public int scorePlayer() { 
     int n = 0; 
     System.out.println("Player Iteration: " + playerIteration); 

     for (int i = 0; i < 100; i++) { 
      System.out.print("I: " + i + " "); 
      n += this.doIteration(); 
     } 
     playerIteration++; 
     return n/2; 
    } 
} 

private int doIteration() { 
     CheckersGame game = new CheckersGame(); 
     game.initializeGame(); 
     game.getBluePlayer().setNetwork(this.network); 

     while (game.getWinner() == -2) { 
      game.turn(); 
     } 
     int winStatus = game.getWinner(); 
     game = null; 

     return winStatus; 
    } 
} 

}

public class LegalMove { 
private GameBoardTile oldTile; 
private GameBoardTile newTile; 
private GameBoardTile jumpedTile; 

private LegalMove moveBefore; 
private LegalMove moveAfter; 

private MoveDirections direction; 

public LegalMove(GameBoardTile oldTile, GameBoardTile newTile, LegalMove moveBefore, LegalMove moveAfter, GameBoardTile jumpedTile, MoveDirections direction) { 
    this.oldTile = oldTile; 
    this.newTile = newTile; 
    this.moveBefore = moveBefore; 
    this.moveAfter = moveAfter; 
    this.jumpedTile = jumpedTile; 
    this.direction = direction; 
} 

public LegalMove(GameBoardTile oldTile, GameBoardTile newTile, LegalMove moveBefore, LegalMove moveAfter, MoveDirections direction) { 
    this.oldTile = oldTile; 
    this.newTile = newTile; 
    this.moveBefore = moveBefore; 
    this.moveAfter = moveAfter; 
    this.direction = direction; 
} 

public ArrayList<GameBoardTile> getTotalJumpedTiles() { 
    ArrayList<GameBoardTile> totalJumpedTiles = new ArrayList<>(); 

    LegalMove moveToCheck = this; 
    while (moveToCheck != null) { 
     totalJumpedTiles.add(moveToCheck.getJumpedTile()); 
     moveToCheck = moveToCheck.getMoveBefore(); 
    } 

    return totalJumpedTiles; 
} 

public GameBoardTile getJumpedTile() { 
    return jumpedTile; 
} 

public int returnNewY() { 
    return newTile.returnY(); 
} 

public int returnNewX() { 
    return newTile.returnX(); 
} 

public GameBoardTile getNewTile() { 
    return newTile; 
} 

public GameBoardTile getOldTile() { 
    return oldTile; 
} 

public void setMoveAfter(LegalMove moveAfter) { 
    this.moveAfter = moveAfter; 
} 

public ArrayList<LegalMove> getPastMoves() { 
    ArrayList<LegalMove> pastMoves = new ArrayList<>(); 
    LegalMove moveToCheck = moveBefore; 
    while(moveToCheck != null) { 
     pastMoves.add(moveToCheck); 
     moveToCheck = moveToCheck.getMoveBefore(); 
    } 

    Collections.reverse(pastMoves); 
    pastMoves.add(this); 
    return pastMoves; 
} 

public LegalMove getMoveBefore() { 
    return moveBefore; 
} 

public LegalMove getMoveAfter() { 
    return moveAfter; 
} 

public String toString() { 
    if (oldTile != null) 
     return "\nOld: " + oldTile + "\nNew: " + newTile + "\n"; 
    else 
     return "\nOld: BEGINNING" + "\nNew: " + newTile + "\n"; 
} 

// Returns the first that needs to be made in this move tree 
public LegalMove getRootMove() { 
    LegalMove moveToCheck = this; 
    while(moveToCheck.getMoveBefore() != null) { 
     moveToCheck = moveToCheck.getMoveBefore(); 
    } 

    return moveToCheck; 
} 

// Captures all "jumped" pieces up to this legal move 
// Returns ArrayList of pieces captured 
public ArrayList<CheckerPiece> captureJumpedPieces() { 
    ArrayList<CheckerPiece> jumpedPieces = new ArrayList<>(); 
    LegalMove moveToCheck = this; 

    while (moveToCheck != null) { 
     if (moveToCheck.getJumpedTile() != null) { 
      jumpedPieces.add(moveToCheck.getJumpedTile().getCurrentPiece()); 
      moveToCheck.getJumpedTile().getCurrentPiece().capturePiece(); 

      moveToCheck = moveToCheck.getMoveBefore(); 
     } else { 
      //System.out.println("Move " + this + " has no jumped pieces"); 
      moveToCheck = moveToCheck.getMoveBefore(); 
     } 
    } 

    return jumpedPieces; 
} 

public CheckerPiece getOldPiece() { 
    return oldTile.getCurrentPiece(); 
} 

public MoveDirections getDirection() { 
    return direction; 
} 

public boolean equals(LegalMove move) { 
    return (oldTile == move.oldTile && newTile == move.newTile && jumpedTile == move.jumpedTile && direction == move.getDirection()); 
} 

public void clearTree() { 
    LegalMove moveToCheck = moveBefore; 

    while (moveToCheck != null) { 
     LegalMove temp = moveToCheck; 
     moveToCheck = moveToCheck.getMoveBefore(); 

     temp.moveAfter = null; 
     temp.jumpedTile = null; 
     temp.oldTile = null; 
     temp.newTile = null; 
     temp.moveAfter = null; 
     temp = null; 
    } 
} 

}

J'ai laissé beaucoup de sections du code et des pièces qui ne sont pas pertinents

+0

Comment sommes-nous supposés trouver une fuite de mémoire sans code? – shmosel

+0

Ce n'est pas bon, mais nous ne pouvons pas vous aider si vous ne montrez pas le code –

+0

Aussi pour une raison quelconque, la fuite de mémoire se produit beaucoup plus rapidement sur mon ordinateur portable Linux que sur mon bureau Windows. – Smaugy

Répondre

0

Je pense que c'est votre problème:

public ArrayList<GameBoardTile> getTotalJumpedTiles() { 
    ArrayList<GameBoardTile> totalJumpedTiles = new ArrayList<>(); 

    LegalMove moveToCheck = this; 
    while (moveToCheck != null) { 
     totalJumpedTiles.add(moveToCheck.getJumpedTile()); 
     moveToCheck = moveToCheck.getMoveBefore(); 
    } 

    return totalJumpedTiles; 
} 

Je ne suis pas le reste du code à voir ce qu'il advient de ce ArrayList, mais si vous continuez à en créer de nouveaux et ne les nettoyez jamais, je peux voir où cela pourrait rapidement devenir une fuite.

+0

ou peut-être que les objets 'LegalMove' semblent également être un problème,' ​​public ArrayList getPastMoves() ' –