1

考虑以下java代码

public class PlayerView implements IPlayerListener
{
    public Player player;

    public PlayerView()
    {
        player = new Player();
        player.listener = this;
    }

    public void onPlayerEvent()
    {

    }
}

public class Player
{
    public IPlayerListener listener;

    public void foo()
    {
        //do something then
        if(this.listener != null)
        {
            this.listener.onPlayerEvent();
        }

    }
}

public interface IPlayerListener
{
    public void onPlayerEvent();
}

这里我有一个 PlayerView 和 Player。Player 需要向 PlayerView 报告事件,所以我创建了一个名为 IPlayerListener 的接口,Player 可能有一个 PlayerListener 对象的引用来报告事件。

(我知道在 java 中这不是创建事件的最佳方式,但我真的不需要“许多侦听器”来使用默认的“addEventListener”模式)

问题一:当 PlayerView 对象设置为 null 时,PlayerView 和 Player 对象都会被 GC 收集吗?

如果是,则继续执行以下代码

public class PlayerView implements IPlayerListener, IPlaylistListener
{
    public Player player;

    public PlayerView()
    {
        player = new Player();
        player.listener = this;
        player.playlist = new Playlist();
        player.playlist.listener = this;
    }

    public void onPlayerEvent()
    {

    }

    public void onPlaylistEvent()
    {

    }
}

public class Player
{
    public Playlist playlist;
    public IPlayerListener listener;

    public void foo()
    {
        //do something then
        if(this.listener != null)
        {
            this.listener.onPlayerEvent();
        }

    }
}

public class Playlist
{
    public IPlaylistListener listener;

    public void bar()
    {
        //do something then
        if(this.listener != null)
        {
            this.listener.onPlaylistEvent();
        }
    }
}

public interface IPlayerListener
{
    public void onPlayerEvent();
}

public interface IPlaylistListener
{
    public void onPlaylistEvent();
}

在这里,我添加了第三个类,播放列表类,播放器也有一个播放列表对象的引用。播放列表也应该有一个监听器/观察器。在这种情况下,PlayerView 也是播放列表侦听器。

问题2:当PlayerView对象设置为null时,这些对象会被GC回收吗?

如果答案 #2 为否,请继续

public class PlayerView implements IPlayerListener, IPlaylistListener
{
    public Player player;

    public PlayerView()
    {
        player = new Player();
        player.listener = this;
        player.playlist = new Playlist();
        player.playlist.parentPlayer = player;
    }

    public void onPlayerEvent()
    {

    }

    public void onPlaylistEvent()
    {

    }
}

public class Player
{
    public Playlist playlist;
    public IPlayerListener listener;

    public void foo()
    {
        //do something then
        if(this.listener != null)
        {
            this.listener.onPlayerEvent();
        }

    }
}

public class Playlist
{
    public Player parentPlayer;

    public void bar()
    {
        //do something then
        if(this.parentPlayer != null)
        {
            if(this.parentPlayer.listener != null)
            {
                if(this.parentPlayer.listener instanceof IPlaylistListener)
                {
                    ((IPlaylistListener) this.parentPlayer.listener).onPlaylistEvent();
                }
            }
        }
    }
}

public interface IPlayerListener
{
    public void onPlayerEvent();
}

public interface IPlaylistListener
{
    public void onPlaylistEvent();
}

这里我将 playlistListener 引用切换为对父 Player 的引用,而不是直接调用 playlistListener,而是检查 playerListener 是否也是一个 PlaylistListener(或者两个接口可以合并为一个)

问题 #3:前面的代码会解决问题并收集所有对象吗?

或者我应该更好地使用第二个代码块并在 PlayerView 对象中找到正确的时间(就像在将 PlayerView 对象从其父视图中删除之前)并至少调用“player.playlist.listener = null;”。

4

1 回答 1

4

重要的是要认识到,理论上不可能预测对象何时会真正被垃圾回收。更具体地说,将字段设置为null不会导致它被收集。相反,它可能会导致它变得无法访问,因此有资格进行垃圾收集。这意味着它可能会在随后的 GC 运行中被收集,但不一定在下一次运行中被收集。(请注意,即使调用System.gc()也不能保证会收集到符合条件的对象。JVM 可以自由地忽略gc()调用。)

注意:可达性是关于对象是否仍然可以被某个活动线程访问。如果一个线程可以跟随一个引用链到达某个对象,那么它是可到达的。自然,链需要以线程可以访问的引用变量开始;例如,线程堆栈上的静态变量或局部变量或参数。


所以对于你的具体问题:

问题一:当 PlayerView 对象设置为 null 时,PlayerView 和 Player 对象都会被 GC 收集吗?

该代码既没有创建PlayerView实例,也没有PlayerView可以为空的变量。我还注意到 Player 和 PlayerView 对象相互指向。此参考周期不会直接影响可达性。尽管这确实意味着如果其中任何一个对象都可以到达,那么两者都是。

因此,如果我们假设只有一个PlayerView变量……而没有Player变量……那么分配null给变量将导致两个对象都变得不可访问,因此有资格被收集。

问题2:当PlayerView对象设置为null时,这些对象会被GC回收吗?

同样,同样需要注意的是,当对 的最后一个可访问引用PlayerView为空时(或当它变得不可访问时),所有三个对象都将有资格被收集。


一些忠告:

  1. 您可能过于担心对象何时以及如何被回收。它很可能没有丝毫区别。
  2. 明确地将事物归零以使它们被收集通常是浪费时间。
  3. 无需担心 Java 中的引用循环。Java GC 不是基于引用计数的,不需要打破循环来使 GC 工作。
于 2012-10-14T15:35:19.503 回答