2017-02-12 5 views
2

Je travaille sur un projet pour essayer de créer un réseau neuronal qui va apprendre à jouer aux checkers en utilisant NEAT. Dans mon jeu de dames, j'utilise la récursivité pour trouver tous les mouvements disponibles qu'un morceau spécifique peut faire. En cours d'exécution du programme normalement, cela fonctionne très bien.Java StackOverflowError causée par la récursivité lors de l'exécution du programme pendant de longues périodes de temps

Le problème est lorsque je lance la partie du programme qui essaie de former le réseau de neurones. Dans mon programme d'entraînement, je cours d'innombrables jeux de dames (10000+) pour essayer d'évoluer mon réseau de neurones. La formation fonctionne bien pour le premier millier de jeux, mais je suis alors frappé par une erreur de stackoverflow causée par la partie récursive du programme qui vérifie les mouvements disponibles. Cela n'a aucun sens pour moi car la méthode fonctionne bien pour le premier millier de jeux, mais elle finit toujours par tomber en panne avec une erreur de stackoverflow.

EDIT: Voici l'aperçu général de la méthode récursive que j'ai découpé un grand nombre des instructions if. Aussi, je m'excuse pour la longueur de ceci, j'aurais probablement pu mettre en application de manière plus lisible et efficace.

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

EDIT # 2: Je pense que cela doit faire quelque chose avec une fuite de mémoire. J'utilisais l'outil Intellij Debug et l'Intellij Memory Analyzer l'a montré. Pourquoi le garbage collector ne détruirait-il pas les arraylists et les objets LegalMove après que j'aie fini de les utiliser?

+0

Postez le code récursion – Aaron

+0

Est-ce votre code qui fait les appels récursifs? Si oui, avez-vous envisagé d'essayer une approche différente - non récursive? – Obicere

+1

Pouvez-vous poster du code pertinent? Pas tout, seulement les parties clés de la récursivité. – degs

Répondre

1

La pile de threads est limitée dans la machine virtuelle Java et peut être configurée via l'option -Xss. Une autre façon de fournir la taille de la pile consiste à la spécifier in the constructor lors de la création manuelle de Thread s.

Si ces alternatives ne sont pas une option, vous pouvez utiliser le Trampoline pattern au lieu d'une implémentation récursive pour être indépendant de toute limitation.

0

Sans aucun code, il est difficile de donner une réponse concrète. Mais, quelques suggestions désinvoltes serait:

  • (En commençant par le capitaine suggestion de type évident) Si vous avez donne pas déjà plus de mémoire pile en utilisant l'option -Xss. Essayez de limiter la quantité d'espace de pile qu'il occupe en limitant la quantité de variables locales dans la portée de la méthode, en essayant de vous assurer que vous avez principalement des références dans la pile et la plupart de vos objets objets sur le tas.

  • rewrite à être itérative au lieu de récursive)