簡體   English   中英

在用Java殺死對象的持有者后,該對象仍然存在嗎?

[英]An object is still alive after I kill its holder in Java?

我一直在努力解決下一個錯誤。 我的程序結構如下

在此處輸入圖片說明

main函數初始化一個Game對象並調用startMainWindow() ,后者初始化一個GameLogic logic對象和一個MainWindow對象(將logic作為參數以及this傳遞給它)。 這兩個對象都是 startMainWindow() 中的局部變量

問題是,比如說當玩家完成游戲並且我想啟動高分GUI時,我會從MainWindow調用_game.startHighScoreWindow() 問題在於GameLogic對象一直在運行! 我通過在GameLogic.actionPerformed()放置控制台寫入命令來輕松地對其進行檢查。 它不會從內存中釋放。 即使我調用this.dispose();也會發生這種情況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。 它的行為與以前相同,也就是說,所有這些對象都位於每個函數的本地。

在回答您的問題時:

在用Java殺死對象的持有者后,該對象仍然存在嗎?

當對象變得不可訪問時,它就有資格刪除。 可到達意味着在尚未返回的某些方法的某些堆棧幀中,存在從static或局部變量開始的對象路徑。

而且有些事情“有些特殊”,例如,線程運行時Thread對象仍然可以訪問...而不管對Thread的其他引用。 類似的情況適用於與GUI相關的對象。


為什么_gameLogic仍在內存中?

不看MCVE的代碼就無法分辨。 (您的UML圖和英語注釋沒有說……而且它們也不一定准確!)

查看您發布的摘錄,您的GameLogic對象仍然可以訪問,因為在MainWindow類的_gameLogic字段中有_gameLogic的引用。 而且MainWindow對象仍然可以訪問,因為它已顯示。

但是正如我們所說,如果您想要正確的答案,則必須使用MCVE。 即,答案要比有根據的猜測更好。

這也值得注意/重復

  • 調用System.gc()是一個壞主意。 它很少起作用。
  • 在變量前加下划線不是標准的Java樣式。 (我稱之為丑陋。)
  • 窗口對象如果當前顯示,則不會產生垃圾回收。 隱藏的引用(在SWT / AWT / JVM中)可確保在顯示窗口對象時可訪問它們。
  • 在擴展JFrame類上調用dispose()不會清除由類本身聲明的字段。 它不了解他們。

問題在於GameLogic對象一直在運行!

如果有東西繼續運行, 那么應該停止它。 這不是GC的工作。

它不會從內存中釋放。

同樣,立即發布所有內容或類似內容也不是GC的工作。 盡力而為的唯一工作就是不會耗盡內存。 它是通過收集垃圾來完成的,但這是一個實現細節。 它可以代替您購買新的RAM,也可以。

您的問題是使用了錯誤的工具來完成工作。

只要提供一個明確的方法來終止您的GameLogic ,就可以完成。 對於在循環中運行的線程,請使用volatile boolean stop變量退出循環。 對於窗口,請使用dispose等。

就這樣。 只是忘了有一個GC。 它不能幫助您了解游戲邏輯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM