Java开发终端国际象棋出现java.lang.OutOfMemoryError如何解决
问题根因
你的java.lang.OutOfMemoryError和JVM内存分配大小无关,完全是循环逻辑错误触发死循环,短时间内生成海量无效Location对象占满堆内存导致的,具体错误点如下:
- 斜向(象)移动的右上、左上两段for循环终止条件完全错误:循环变量
i逐次递减,你写的终止判断是i < this.getBoard().getRows(),不管i减到0、-1000还是更小的负数,都永远满足“小于棋盘行数”的条件,循环根本不会停止。 - 车的左移段for循环终止条件写反:循环变量
i从col-1开始逐次递减,终止判断却写的是i < this.getBoard().getColumns(),同样是i永远满足判断条件的死循环。 - 所有滑动遍历逻辑都没有在碰到棋子后终止循环:国际象棋象、车、后这类滑动棋子,沿固定方向移动时碰到第一个棋子就无法继续前进,你现在碰到棋子后只是把位置加入吃子列表,没有
break跳出循环,哪怕坐标越界循环还会持续运行。 - 斜向循环的终止条件只判断了行坐标边界,完全没校验列坐标
possibleCol是否在棋盘列范围内,哪怕列已经越界,只要行还满足条件循环就不会停。
修复方案
修复核心规则:沿每个方向遍历时,for循环的终止条件必须同时校验行、列坐标是否在棋盘边界内;一旦遍历到任意棋子,不管是己方还是对方,处理完位置后立刻break终止当前方向的遍历,不允许穿子移动。
修复后的斜向(象)移动逻辑
// 右下方向:行递增,列递增 int possibleCol = col + 1; for (int i = row + 1; i < this.getBoard().getRows() && possibleCol < this.getBoard().getColumns(); i++, possibleCol++){ Piece pieceAt = this.getBoard().getPieceAt(i, possibleCol); Location location = new Location(i, possibleCol); if (pieceAt == null){ possibleMoves.add(location); } else { possibleKills.add(location); break; } } // 右上方向:行递减,列递增 possibleCol = col + 1; for (int i = row - 1; i >= 0 && possibleCol < this.getBoard().getColumns(); i--, possibleCol++){ Piece pieceAt = this.getBoard().getPieceAt(i, possibleCol); Location location = new Location(i, possibleCol); if (pieceAt == null){ possibleMoves.add(location); } else { possibleKills.add(location); break; } } // 左下方向:行递增,列递减 possibleCol = col - 1; for (int i = row + 1; i < this.getBoard().getRows() && possibleCol >= 0; i++, possibleCol--){ Piece pieceAt = this.getBoard().getPieceAt(i, possibleCol); Location location = new Location(i, possibleCol); if (pieceAt == null){ possibleMoves.add(location); } else { possibleKills.add(location); break; } } // 左上方向:行递减,列递减 possibleCol = col - 1; for (int i = row - 1; i >= 0 && possibleCol >= 0; i--, possibleCol--){ Piece pieceAt = this.getBoard().getPieceAt(i, possibleCol); Location location = new Location(i, possibleCol); if (pieceAt == null){ possibleMoves.add(location); } else { possibleKills.add(location); break; } }
修复后的车直线移动逻辑
重点修正左移方向的循环终止条件,所有方向碰到棋子后立刻break:
// 下移方向:行递增,列固定 int possibleRow = row + 1; for (int i = possibleRow; i < this.getBoard().getRows(); i++){ Piece pieceAt = this.getBoard().getPieceAt(i, col); Location location = new Location(i, col); if (pieceAt == null){ possibleMoves.add(location); } else { possibleKills.add(location); break; } } // 上移方向:行递减,列固定 possibleRow = row - 1; for (int i = possibleRow; i >= 0; i--){ Piece pieceAt = this.getBoard().getPieceAt(i, col); Location location = new Location(i, col); if (pieceAt == null){ possibleMoves.add(location); } else { possibleKills.add(location); break; } } // 右移方向:列递增,行固定 int possibleCol = col + 1; for (int i = possibleCol; i < this.getBoard().getColumns(); i++){ Piece pieceAt = this.getBoard().getPieceAt(row, i); Location location = new Location(row, i); if (pieceAt == null){ possibleMoves.add(location); } else { possibleKills.add(location); break; } } // 左移方向:列递减,行固定 possibleCol = col - 1; for (int i = possibleCol; i >= 0; i--){ Piece pieceAt = this.getBoard().getPieceAt(row, i); Location location = new Location(row, i); if (pieceAt == null){ possibleMoves.add(location); } else { possibleKills.add(location); break; } }
额外优化建议
- 后的合法移动直接复用象+车的移动逻辑即可,不需要重复编写8个方向的遍历循环。
- 补充阵营判断:当前
possibleKills会把己方棋子也加入可吃子列表,需要新增判断,只有敌方棋子所在位置才能加入吃子列表;碰到己方棋子直接break,不要加入任何可移动列表。 - 可以把8个移动方向的行、列偏移量提前存在二维数组里,比如
int[][] dirs = {{1,1}, {1,-1}, {-1,1}, {-1,-1}, {1,0}, {-1,0}, {0,1}, {0,-1}},遍历方向数组统一处理滑动逻辑,避免重复写8段高度相似的for循环,减少写错条件的概率。
内容的提问来源于stack exchange,提问作者VictorOrtins
相关产品推荐
相关产品推荐

