Java程序一开始运行正常,但随后导致内存泄漏

Java程序一开始运行正常,但随后导致内存泄漏,java,memory-leaks,heap,heap-memory,Java,Memory Leaks,Heap,Heap Memory,我正在做一个项目,尝试使用神经网络来学习如何玩跳棋游戏。在训练我的网络时,我必须运行许多游戏的模拟(10000多个游戏)。当使用Intellij的内存查看器检查堆内存时,一切似乎正常。每个CheckerGame对象及其相关字段(CheckerPieces、GameBoard等)似乎最终都会被java的垃圾收集器回收。这意味着一旦跳棋游戏完成,游戏的资源就会被正确地处理 然而,在运行了一段时间的训练程序之后,Java的垃圾收集器似乎决定停止回收我的游戏对象,然后随着游戏对象的堆积,我最终得到一个O

我正在做一个项目,尝试使用神经网络来学习如何玩跳棋游戏。在训练我的网络时,我必须运行许多游戏的模拟(10000多个游戏)。当使用Intellij的内存查看器检查堆内存时,一切似乎正常。每个CheckerGame对象及其相关字段(CheckerPieces、GameBoard等)似乎最终都会被java的垃圾收集器回收。这意味着一旦跳棋游戏完成,游戏的资源就会被正确地处理

然而,在运行了一段时间的训练程序之后,Java的垃圾收集器似乎决定停止回收我的游戏对象,然后随着游戏对象的堆积,我最终得到一个OutOfMemory错误。 这是我所说的一个例子

显然有一些内存泄漏,但这对我来说毫无意义,因为该程序大部分时间都正确地回收了游戏资源

编辑:代码

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

训练代码(记分员不断被调用,游戏结果返回到神经网络):

公共类NeuralPlayerRandom{
专用NEATNetwork网络;
私有静态整数播放操作=1;
公共NeutnalPlayerLandom(NEATNetwork网络){
这个网络=网络;
}
公共整数记分员(){
int n=0;
System.out.println(“玩家迭代:+playerOperation”);
对于(int i=0;i<100;i++){
系统输出打印(“I:+I+”);
n+=this.doIteration();
}
播放操作++;
返回n/2;
}
}
私有内部迭代(){
CheckersGame=新CheckersGame();
game.initializeGame();
game.getBluePlayer().setNetwork(this.network);
while(game.getWinner()=-2){
游戏。转身();
}
int winStatus=game.getWinner();
game=null;
返回温斯塔斯;
}
}
}

public class LegalMove{
私人游戏板;
私有游戏板;
私人游戏板;跳转文件;
私人法律动议;
私人法律动议;
私人移动方向;
公共LegalMove(GameBoardTile旧文件、GameBoardTile新文件、LegalMove之前移动、LegalMove之后移动、GameBoardTile跳转文件、移动方向){
this.oldTile=oldTile;
this.newTile=newTile;
this.moveBefore=moveBefore;
this.moveAfter=moveAfter;
this.jumpedTile=jumpedTile;
这个方向=方向;
}
公共LegalMove(GameBoardTile oldTile、GameBoardTile NewFile、LegalMove moveBefore、LegalMove moveAfter、MoveDirections){
this.oldTile=oldTile;
this.newTile=newTile;
this.moveBefore=moveBefore;
this.moveAfter=moveAfter;
这个方向=方向;
}
公共阵列列表GetTotalJumpedFiles(){
ArrayList totalJumpedTiles=新的ArrayList();
LegalMove moveToCheck=此;
while(moveToCheck!=null){
添加(moveToCheck.getJumpedTile());
moveToCheck=moveToCheck.getMoveBefore();
}
返回总跳跃文件;
}
公共游戏板Tile GetJumpedFile(){
返回跳转文件;
}
public int returnNewY(){
return newfile.returnY();
}
public int returnNewX(){
return newfile.returnX();
}
公共GameBoardTile GetNewFile(){
返回新文件;
}
公共GameBoardTile getOldTile(){
归还旧瓷砖;
}
公共无效setMoveAfter(LegalMove moveAfter){
this.moveAfter=moveAfter;
}
公共阵列列表getPastMoves(){
ArrayList pastMoves=新建ArrayList();
LegalMove moveToCheck=moveBefore;
while(moveToCheck!=null){
添加(moveToCheck);
moveToCheck=moveToCheck.getMoveBefore();
}
集合。反向(过去移动);
添加(这个);
回击动作;
}
公共法律移动getMoveBefore(){
之前返回;
}
公共法律移动getMoveAfter(){
返回后移动;
}
公共字符串toString(){
如果(oldTile!=null)
返回“\nOld:+oldTile+”\n新:+newTile+“\n”;
其他的
返回“\nOld:开始“+”\n新:“+newfile+”\n”;
}
//返回此移动树中需要执行的第一个操作
public LegalMove getRootMove(){
LegalMove moveToCheck=此;
while(moveToCheck.getMoveBefore()!=null){
moveToCheck=moveToCheck.getMoveBefore();
}
返回moveToCheck;
}
//捕捉到这一合法行动之前的所有“跳跃”片段
//返回捕获的片段的ArrayList
公共阵列列表captureJumpedPieces(){
ArrayList jumpedPieces=新建ArrayList();
LegalMove moveToCheck=此;
while(moveToCheck!=null){
if(moveToCheck.getJumpedFile()!=null){
添加(moveToCheck.getJumpedFile().getCurrentPiece());
移动到check.getJumpedFile().getCurrentPiece().capturePiece();
moveToCheck=moveToCheck.getMoveBefore();
}否则{
//System.out.println(“移动”+此+“没有跳转片段”);
moveToCheck=moveToCheck.getMoveBefore();
}
}
返回跳线;
}
公共校验页getoldpoice(){
返回oldTile.getCurrentPiece();
}
公共移动方向getDirection(){
返回方向;
}
公共布尔等于(LegalMove移动){
返回(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.getMoveBefore();
temp.moveAfter=null;
临时跳线文件=空;
temp.oldTile=null;
temp.newfile=null;
temp.moveAfter=null;
温度=零;
}
}
}


我遗漏了许多代码部分和不相关的片段

我认为这是您的问题:

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

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

    return totalJumpedTiles;
}
公共阵列列表getTotalJumpe
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;
    }
}
public ArrayList<GameBoardTile> getTotalJumpedTiles() {
    ArrayList<GameBoardTile> totalJumpedTiles = new ArrayList<>();

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

    return totalJumpedTiles;
}