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」パターンを使用するために「多くのリスナー」は必要ありません)

質問 #1: 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();
}

ここでは、3 番目のクラスである Playlist クラスを追加しました。このクラスは、Player にもプレイリスト オブジェクトへの参照があります。また、プレイリストにはリスナー/オブザーバーが必要です。この場合、PlayerView は Playlist リスナーでもあります。

質問 #2: PlayerView オブジェクトが null に設定されている場合、これらのオブジェクトは GC によって収集されますか?

答え #2 が NO の場合は、続行してください

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 であるかどうかを確認します (または、両方のインターフェイスを 1 つにマージできます)。

質問 #3: 前のコードで問題が解決し、すべてのオブジェクトが収集されますか?

または、2 番目のコード ブロックを使用して、PlayerView オブジェクトで適切な時間を見つけ (PlayerView オブジェクトが親ビューから削除される前など)、少なくとも "player.playlist.listener = null;" を呼び出す必要があります。

4

1 に答える 1

4

オブジェクトが実際にいつガベージ コレクションされるかを予測することは理論的に不可能であることを理解することが重要です。より具体的には、フィールドを に設定しnullても収集されません。むしろ、到達不能になり、ガベージ コレクションの対象となる可能性があります。つまり、後続の GC 実行で収集される可能性がありますが、必ずしも次の実行で収集されるとは限りません。(また、呼び出しによってもSystem.gc()適格なオブジェクトが収集されるとは限らないことに注意してください。JVM はgc()呼び出しを自由に無視できます。)

注: 到達可能性は、ライブ スレッドがオブジェクトに引き続きアクセスできるかどうかにかかっています。スレッドが一連の参照をたどって何らかのオブジェクトに到達できる場合、そのスレッドは到達可能です。当然、チェーンは、スレッドがアクセスできる参照変数から開始する必要があります。たとえば、スレッドのスタック上の静的変数またはローカル変数または引数です。


だからあなたの特定の質問に:

質問 #1: PlayerView オブジェクトが null に設定されている場合、PlayerView と Player オブジェクトの両方が GC によって収集されますか?

PlayerViewこのコードは、インスタンスを作成していないか、 nullPlayerViewになる可能性のある変数を持っていません。また、Player オブジェクトと PlayerView オブジェクトが相互にポイントしていることにも注意してください。この参照サイクルは、到達可能性に直接影響しません。ただし、どちらかのオブジェクトが到達可能であれば、両方が到達可能であることを意味します。

PlayerViewしたがって、変数が 1 つしかなく、変数がないと仮定すると、変数Playerに代入nullすると、両方のオブジェクトが到達不能になり、収集の対象となります。

質問 #2: PlayerView オブジェクトが null に設定されている場合、これらのオブジェクトは GC によって収集されますか?

繰り返しますが、同じ注意事項がありますが、 への最後の到達可能な参照PlayerViewが null になった場合 (または到達不能になった場合)、3 つのオブジェクトすべてが収集対象になります。


いくつかのアドバイス:

  1. おそらく、オブジェクトがいつ、どのように再利用されるかについて心配しすぎているでしょう。ほとんどの場合、ほとんど違いはありません。
  2. それらを明示的に無効にしてそれらを収集することは、一般的に時間の無駄です。
  3. Java では参照循環について心配する必要はありません。Java GC は参照カウントに基づいていないため、GC を機能させるためにサイクルを中断する必要はありません。
于 2012-10-14T15:35:19.503 に答える