2017-02-12 72 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选项已经给它更多的堆栈存储器。

  • 尝试通过限制方法范围内局部变量的数量来限制它占用的堆栈空间量,方法是确保大多数堆栈内存中的引用以及堆中的大多数对象对象都被引用。

  • 重写它是重复的,而不是递归;)