这些物体会被GC收集吗?

时间:2012-10-14 12:53:20

标签: java android garbage-collection observer-pattern

考虑以下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。播放器需要向PlayerView报告事件,因此我创建了一个名为IPlayerListener的接口,Player可以为PlayerListener对象提供报告事件的参考。

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

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

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

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();
}

这里我添加了第三个类Playlist类,Player也有播放列表对象的引用。 播放列表也应该有一个监听器/观察者。在这种情况下,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;”。

1 个答案:

答案 0 :(得分:4)

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

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


那么就你的具体问题而言:

  

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

代码既不会创建PlayerView实例,也不会生成可以为空的PlayerView变量。我还注意到Player和PlayerView对象相互指向。此参考周期不会直接影响可达性。虽然它确实意味着如果任何一个对象都可以访问,那么两者都是。

因此,如果我们假设只有一个PlayerView变量......而且没有Player变量......那么将null赋值给变量会导致两个对象无法访问因此有资格被收集。

  

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

同样,在相同的警告中,当PlayerView的最后一个可到达引用被取消(或者当它变得无法访问时)时,所有三个对象都有资格被收集。


一些建议:

  1. 您可能会过多地担心对象何时以及如何被回收。它很可能没有丝毫差别。
  2. 明确地将事物归零以使其被收集通常是浪费时间。
  3. 无需担心Java中的引用周期。 Java GC不基于引用计数,并且不需要中断循环以使GC工作。
相关问题