在Java中删除它的持有者后,一个对象仍然存在?

时间:2018-06-04 22:27:08

标签: java garbage-collection

我正在努力解决下一个bug几个小时。我的程序结构如下

enter image description here

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。它保持与以前相同的行为,即每个函数都具有所有这些对象。

2 个答案:

答案 0 :(得分:3)

回答你的问题:

  

我用Java杀了它的持有者后,一个对象还活着吗?

当一个对象无法访问时,它有资格被删除。 Reachable意味着从某个方法的某个堆栈框架中的static或局部变量开始,该对象有一些路径,但尚未返回。

有些东西有点特别"例如,当线程正在运行时,Thread对象仍然可以访问...无论对Thread的其他引用如何。类似的东西也适用于与GUI相关的对象。

  

为什么_gameLogic仍在内存中?

如果没有看到MCVE的代码,就无法分辨。 (你的UML图表和英文评论都没有说......反正他们也不一定准确!)

查看您发布的代码段,您的GameLogic对象仍然可以访问,因为_gameLogic类的MainWindow字段中有对此引用。 <{1}}对象仍然可以访问,因为它已显示。

但正如我们所说,如果你想得到正确答案,那么MCVE是必要的;即答案比有根据的猜测更好。

值得注意/重复

  • 致电MainWindow是一个坏主意。它很少奏效。
  • 使用下划线前缀变量不是标准Java样式。 (我称之为丑陋。)
  • 窗口对象如果当前显示则不会收集垃圾。隐藏引用(在SWT / AWT / JVM中)确保窗口对象在显示时可以访问。
  • 在扩展System.gc()的类上调用dispose()不会清除类本身声明的字段。它并不了解它们。

答案 1 :(得分:1)

  

问题是GameLogic对象一直在运行!

如果某些内容一直在运行,那么应该停止它。这不是GC的工作。

  

它不会从内存中释放出来。

同样,GC的工作不是立即或类似地发布所有内容。努力尝试你唯一的工作就是不会耗尽内存。它通过收集垃圾来实现,但这是一个实现细节;它可以为你买新的RAM而且没问题。

您的问题是使用了错误的工具。

只需提供一种明确的方法来终止您的GameLogic即可。对于在循环中运行的线程,使用volatile boolean stop变量退出循环。对于窗口,请使用dispose等....

这就是全部。忘记有一个GC。它并不能帮助你解决游戏逻辑问题。

相关问题