2017-02-12 116 views
2

我正在研究一個項目,嘗試創建一個神經網絡,它將學習如何使用NEAT玩跳棋。在我的跳棋遊戲中,我使用遞歸來查找特定棋子可以製作的所有可用棋步。通常運行程序,效果很好。長時間運行程序時遞歸導致的Java StackOverflowError

問題是當我運行試圖訓練神經網絡的程序部分時。在我的訓練計劃中,我運行無數跳棋遊戲(10000+)來嘗試發展我的神經網絡。訓練對於上千場比賽非常有用,但後來我遇到了一個由檢查可用動作的程序的遞歸部分引起的stackoverflow錯誤。這對我來說沒有任何意義,因爲這種方法對於前1000場比賽來說工作得很好,但最終總是會因爲一個stackoverflow錯誤而崩潰。

編輯:這裏是遞歸方法的主要概述,我剪出了很多if語句。此外,我對此的長度表示歉意,我可能會以更具可讀性和更高效的方式實施。

private void checkAvailableTilesRecursion(GameBoardTile oldTile, LegalMove newMove) { 

    ArrayList<LegalMove> recursiveCheck = new ArrayList<>(); 

    // Find available pieces if piece is king 
    if (!edgePiece) { 
     // Code to get the different tiles adjacent to this tile 

     if (legalMoveCheckerPiece.getIsKing()) { 
      // Up right 
      // If the tile up right is clear 
       LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() - 2][newMove.returnNewX() + 2], newMove, null, upRight, MoveDirections.UP_RIGHT); 
       newMove.setMoveAfter(move); 
       availableLegalMoves.add(move); // defined elsewhere 
       recursiveCheck.add(move); 
      } 
      // Up left 
      // If the tile up left is clear 
       LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() - 2][newMove.returnNewX() - 2], newMove, null, upLeft, MoveDirections.UP_LEFT); 
       newMove.setMoveAfter(move); 
       availableLegalMoves.add(move); // defined elsewhere 
       recursiveCheckRecursive.add(move); 
      } 

      // Down right 
      // If tile down right is clear 
       LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() + 2][newMove.returnNewX() + 2], newMove, null, downRight, MoveDirections.DOWN_RIGHT); 
       newMove.setMoveAfter(move); 
       availableLegalMoves.add(move); // defined elsewhere 
       recursiveCheckRecursive.add(move); 
      } 

      //Down left 
      // If tile down left is clear 
       LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() + 2][newMove.returnNewX() - 2], newMove, null, downLeft, MoveDirections.DOWN_LEFT); 
       newMove.setMoveAfter(move); 
       availableLegalMoves.add(move); // defined elsewhere 
       recursiveCheckRecursive.add(move); 
      } 

     } else { 

      // Find available tiles for normal pieces 
      if (legalMoveCheckerPiece.getColor() == PieceColors.BLUE) { 

       // Up right 
       // If tile up right is clear 
        LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() - 2][newMove.returnNewX() + 2], newMove, null, upRight, MoveDirections.UP_RIGHT); 
        newMove.setMoveAfter(move); 
        availableLegalMoves.add(move); 
        recursiveCheckRecursive.add(move); 
       } 
       // Up left 
       // If tile up left is clear 
        LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() - 2][newMove.returnNewX() - 2], newMove, null, upLeft, MoveDirections.UP_LEFT); 
        newMove.setMoveAfter(move); 
        availableLegalMoves.add(move); 
        recursiveCheckRecursive.add(move); 
       } 

      } else { 
       // Red Team 
       // Down right 
       // If tile down right is clear 
        LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() + 2][newMove.returnNewX() + 2], newMove, null, downRight, MoveDirections.DOWN_RIGHT); 
        newMove.setMoveAfter(move); 
        availableLegalMoves.add(move); 
        recursiveCheckRecursive.add(move); 
       } 

       //Down left 
       // If tile down left is clear 
        LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() + 2][newMove.returnNewX() - 2], newMove, null, downLeft, MoveDirections.DOWN_LEFT); 
        newMove.setMoveAfter(move); 
        availableLegalMoves.add(move); 
        recursiveCheckRecursive.add(move); 
       } 
      } 
     } 
    } 

    if (recursiveCheckRecursive.size() > 0) { 
     for (LegalMove moveToCheck : recursiveCheckRecursive) { 
      checkAvailableTilesRecursion(newMove.getNewTile(), moveToCheck); 
     } 
    } 
} 

編輯#2:我認爲這必須做一些內存泄漏。我正在使用Intellij調試工具,Intellij Memory Analyzer顯示了這一點。 Memory Leak

爲什麼垃圾收集器在我完成使用它們之後不會破壞arraylist和LegalMove對象?

+0

後遞歸碼 – Aaron

+0

是你的代碼,即拍即遞歸調用?如果是這樣,你有沒有考慮嘗試一種不同的非遞歸方法? – Obicere

+1

你能發佈一些相關的代碼嗎?不是全部,只是遞歸的關鍵部分。 – degs

回答

1

線程堆棧在JVM中是有限的,可以通過-Xss選項進行配置。另一種提供堆棧大小的方法是在手動創建Thread時指定in the constructor

如果這些替代方案無法選擇,您可以考慮使用Trampoline pattern而不是遞歸實現,以獨立於任何限制。

0

沒有任何代碼,很難給出具體的答案。但是,幾個副手的建議是:

  • (與船長明顯的類型建議開始),如果你還沒有使用-Xss選項已經給它更多的堆棧存儲器。

  • 嘗試通過限制方法範圍內局部變量的數量來限制它佔用的堆棧空間量,方法是確保大多數堆棧內存中的引用以及堆中的大多數對象對象都被引用。

  • 重寫它是重複的,而不是遞歸;)