我正在努力解决下一个bug几个小时。我的程序结构如下
main
函数初始化Game
对象并调用startMainWindow()
,初始化GameLogic logic
对象和MainWindow
对象(传递logic
作为一个论点,还有this
)。 这两个对象都是 startMainWindow()
中的局部变量。
问题是,当玩家完成游戏并且我想要启动高分GUI时,我会使用_game.startHighScoreWindow()
来呼叫MainWindow
。
问题是GameLogic
对象一直在运行!我通过在GameLogic.actionPerformed()
中放置一个控制台写命令来轻松检查它。它不会从内存中释放出来。即使我在this.dispose();
之前致电_game.startHighScoreWindow()
,也会发生这种情况。
为什么_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);
}
主窗口:
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。它保持与以前相同的行为,即每个函数都具有所有这些对象。
答案 0 :(得分:3)
回答你的问题:
我用Java杀了它的持有者后,一个对象还活着吗?
当一个对象无法访问时,它有资格被删除。 Reachable意味着从某个方法的某个堆栈框架中的static
或局部变量开始,该对象有一些路径,但尚未返回。
有些东西有点特别"例如,当线程正在运行时,Thread
对象仍然可以访问...无论对Thread
的其他引用如何。类似的东西也适用于与GUI相关的对象。
为什么_gameLogic仍在内存中?
如果没有看到MCVE的代码,就无法分辨。 (你的UML图表和英文评论都没有说......反正他们也不一定准确!)
查看您发布的代码段,您的GameLogic
对象仍然可以访问,因为_gameLogic
类的MainWindow
字段中有对此引用。 <{1}}对象仍然可以访问,因为它已显示。
但正如我们所说,如果你想得到正确答案,那么MCVE是必要的;即答案比有根据的猜测更好。
值得注意/重复
MainWindow
是一个坏主意。它很少奏效。System.gc()
的类上调用dispose()
不会清除类本身声明的字段。它并不了解它们。答案 1 :(得分:1)
问题是GameLogic对象一直在运行!
如果某些内容一直在运行,那么你应该停止它。这不是GC的工作。
它不会从内存中释放出来。
同样,GC的工作不是立即或类似地发布所有内容。努力尝试你唯一的工作就是不会耗尽内存。它通过收集垃圾来实现,但这是一个实现细节;它可以为你买新的RAM而且没问题。
您的问题是使用了错误的工具。
只需提供一种明确的方法来终止您的GameLogic
即可。对于在循环中运行的线程,使用volatile boolean stop
变量退出循环。对于窗口,请使用dispose
等....
这就是全部。忘记有一个GC。它并不能帮助你解决游戏逻辑问题。