我为下一个bug苦苦挣扎了好几个小时。我的程序结构如下
main
函数初始化一个Game
对象并调用startMainWindow()
,后者初始化一个GameLogic logic
对象和一个MainWindow
对象(将logic
作为参数传递给它,还将this
作为参数传递给它)。这两个对象都是 startMainWindow()
中的局部变量。
问题是,假设玩家玩完游戏后,我想启动高分图形用户界面,我从MainWindow
调用_game.startHighScoreWindow()
。问题是GameLogic
对象一直在运行!通过在GameLogic.actionPerformed()
中输入控制台写命令,我可以轻松地检查它。它不会从内存中释放。即使我在_game.startHighScoreWindow()
之前调用this.dispose();
,也会发生这种情况。
为什么_gameLogic
还在内存中?
下面是一些代码:
PacmanGame:
public void startMainWindow(int levelIndex, int levelsDone, int score) {
gameGui = null; //desperate attempt
highScoreGui = null;
mainMenuGui = null;
spaceGui = null;
gameLogic = null;
System.gc();
gameLogic = new GameLogic(_sprites, _levels[levelIndex], levelsDone, score);
gameGui = new MainWindowGui(this, gameLogic, _sprites, _levels);
}
public void startHighscoreGui(int score, String time) {
gameGui = null;
highScoreGui = null;
mainMenuGui = null;
spaceGui = null;
gameLogic = null;
System.gc();
highScoreGui = new HighscoreGui(this, score, time);
}
MainWindow:
public class MainWindow extends JFrame implements KeyListener {
private PacmanGame _game;
private GameLogic _gameLogic;
private GamePanel _gamePanel; //JPanel
private ToolbarPanel _toolbarPanel; //JPanel
private Sprite[] _sprites;
private Level[] _levels;
public MainWindow(PacmanGame game, GameLogic gameLogic, Sprite[] sprites, Level[] levels) {
// create our window
super("Pacman");
// initialize fields
_game = game;
_sprites = sprites;
_gameLogic = gameLogic;
_levels = levels;
this._gamePanel = new GamePanel(_gameLogic, _sprites);
this._toolbarPanel = new ToolbarPanel(_gameLogic, sprites, this);
...
}
public void playerWon(String time) {
Level levelObj = _gameLogic.getLevelObject();
int nextLevelIndex = (levelObj.getNum()) % 3;
if(_gameLogic.getLevel() == 3) //done!
{
this.dispose();
_game.startHighscoreGui(_gameLogic.getScore(), time);
}
else //next level
{
_gameLogic.nextLevel(_levels[nextLevelIndex]);
}
}
编辑:在一次孤注一掷的尝试中,我尝试在PacmanGame中创建所有的GUI和GameLogic静态变量,然后每次在PacmanGame中调用函数时将它们设置为null。它保持与以前一样的行为,也就是说,所有这些对象都是每个函数的本地对象。
发布于 2018-06-05 06:53:35
在回答您的问题时:
一个对象在我杀死它的持有者后仍然活着吗?
当一个对象变得不可访问时,它就有资格被删除。可到达的意思是,在某个方法的某个堆栈框架中,存在从static
或局部变量开始的、尚未返回的对象的路径。
还有一些事情是“有点特殊”的,例如,Thread
对象在线程运行时保持可达状态……而不考虑对Thread
的其他引用。类似的事情也适用于与GUI相关的对象。
为什么_gameLogic还在内存中?
如果不看到MCVE的代码,就无法判断。(您的UML图和英语注释没有说...而且它们也不一定是准确的!)
查看您发布的代码片段,您的GameLogic
对象仍然是可访问的,因为在MainWindow
类的_gameLogic
字段中有对它的引用。并且MainWindow
对象仍然是可访问的,因为它被显示。
但正如我们所说的,如果你想要正确的答案,MCVE是必要的;即比有根据的猜测更好的答案。
这也值得注意/重复。
System.gc()
不是一个好主意。带下划线的works.JFrame
的类上的dispose()
不会清理类本身声明的字段。它不知道他们的情况。发布于 2018-06-05 20:41:57
问题是GameLogic对象一直在运行!
如果某个东西一直在运行,那么你就应该停止它。这不是GC的工作。
它不会从内存中释放。
同样,GC的工作不是立即发布所有内容或类似的内容。唯一的工作就是努力,你不会耗尽你的内存。它通过收集垃圾来做到这一点,但这是一个实现细节;它可以为您购买新的RAM,这样就没问题了。
你的问题是使用了错误的工具。
只需提供一个显式的方法来终止您的GameLogic
,就完成了。对于在循环中运行的线程,使用volatile boolean stop
变量退出循环。对于窗口,使用dispose
等...
就这样。忘了有个GC吧。它不是用来帮助你理解游戏逻辑的。
https://stackoverflow.com/questions/50689605
复制相似问题