7

次のコードがあります。

private final List<WeakReference<T>> slaves;

public void updateOrdering() {
  // removes void weak references 
  // and ensures that weak references are not voided 
  // during subsequent sort 
  List<T> unwrapped = unwrap();
  assert unwrapped.size() == this.slaves.size();
  // **** could be reimplemented without using unwrap() ****
  Collections.sort(this.slaves, CMP_IDX_SLV);
  unwrapped = null;// without this, ....
}

メソッドは、 の弱い参照によって参照される のunwrap()リストを作成するだけで 、副作用として の弱い参照を参照しなくなります。次に、の各メンバーがsomeを参照することに依存する種類があります。それ以外の場合、コードは を生成します。TslavesnullslavesslavesTNullPointerException

unwrappedは各Tinの参照を保持するためslaves、並べ替え中に GC によって a が削除されることはありませんT。最後に、unwrapped = nullラップされていない参照を削除して、GC を再び解放します。かなりうまくいくようです。

今私の質問:

これを削除すると、負荷がかかった状態で多くのテストを実行したときに発生しますunwrapped = null;NullPointerExceptions私は、JIT が排除されていると思われるため、ソート中にList<T> unwrapped = unwrap(); GC がスレーブ内の に適用されます。T

別の説明はありますか?私に同意する場合、これは JIT のバグですか?

unwrapped = null個人的には必要ないと思いunwrappedますupdateOrdering()。何が最適化され、何が最適化されないかという仕様はありますか?

それとも私は間違った方法で物事をしましたか?で弱い参照を許可するようにコンパレータを変更するという考えがありますnull。あれについてどう思う?

提案をありがとう。

アドオン (1)

ここで、不足している情報をいくつか追加したいと思います: まず、Java バージョン: Java バージョン "1.7.0_45" OpenJDK ランタイム環境 (IcedTea 2.4.3) (suse-8.28.3-x86_64) OpenJDK 64 ビット サーバー VM (ビルド) 24.45-b08、混合モード)

次に、誰かがメソッドのアンラップを見たいと思った

private synchronized List<T> unwrap() {
List<T> res = new ArrayList<T>();
T cand;
WeakReference<T> slvRef;
Iterator<WeakReference<T>> iter = this.slaves.iterator();
while (iter.hasNext()) {
    slvRef = iter.next();
    cand = slvRef.get();
    if (cand == null) {
    iter.remove();
    continue;
    }
    assert cand != null;
    res.add(cand);
} // while (iter.hasNext())

return res;
}

反復中に、無効な参照が削除されることに注意してください。実際、私はこの方法を

private synchronized List<T> unwrap() {
List<T> res = new ArrayList<T>();
for (T cand : this) {
    assert cand != null;
    res.add(cand);
}

return res;
}

私自身のイテレータを使用していますが、機能的にはこれは同じはずです。

次に、誰かがスタックトレースを欲しがります。これがその一部です。

 java.lang.NullPointerException: null
 at WeakSlaveCollection$IdxComparator.compare(WeakSlaveCollection.java:44)
 at WeakSlaveCollection$IdxComparator.compare(WeakSlaveCollection.java:40)
 at java.util.TimSort.countRunAndMakeAscending(TimSort.java:324)
 at java.util.TimSort.sort(TimSort.java:189)
 at java.util.TimSort.sort(TimSort.java:173)
 at java.util.Arrays.sort(Arrays.java:659)
 at java.util.Collections.sort(Collections.java:217)
 at WeakSlaveCollection.updateOrdering(WeakSlaveCollection.java:183)

これは、リターンのある行であるコンパレーターを指しています。

static class IdxComparator 
    implements Comparator<WeakReference<? extends XSlaveNumber>> {
    public    int compare(WeakReference<? extends XSlaveNumber> slv1, 
              WeakReference<? extends XSlaveNumber> slv2) {
        return slv2.get().index()-slv1.get().index();
    }
} // class IdxComparator 

そして最後に、

 private final static IdxComparator CMP_IDX_SLV = new IdxComparator();

重要な定数です。

アドオン (2)

updateOrdering() に「unwrapped = null」が存在する場合でも、実際に NPE が発生することが確認されました。

jit の最適化後に厳密な参照が保持されない場合、Java ランタイムによって弱い参照が削除されることがあります。ソースコードはまったく重要ではないようです。

次の方法で問題を解決しました。

public void updateOrdering() {
Collections.sort(this.slaves, CMP_IDX_SLV);
}

スレーブがガベージ コレクションされるのを防ぐために装飾を挿入せず、CMP_IDX_SLV のコンパレータを有効にして null への弱い参照を処理します。

    public    int compare(WeakReference<? extends XSlaveNumber> slv1, 
              WeakReference<? extends XSlaveNumber> slv2) {
    XSlaveNumber sSlv1 = slv1.get();
    XSlaveNumber sSlv2 = slv2.get();
    if (sSlv1 == null) {
    return sSlv2 == null ? 0 : -1;
    }
    if (sSlv2 == null) {
    return +1;
    }
    assert sSlv1 != null && sSlv2 != null;

    return sSlv2.index()-sSlv1.index();
    }

副作用として、基になるリスト List> slaves; を並べ替えます。無効な弱参照をリストの最後に置き、後で収集できるようにします。

4

3 に答える 3

0

あなたの質問

unwrapped = null; を削除すると これは、NullPointerException負荷がかかった状態で多くのテストを実行する場合に発生します。

私の理解によれば、それが違いを生むとは思いませんunwrapped = null;
はい、参照されているオブジェクトがGCされる可能性が高まることもあると読みましたが、メソッドが終了するとスコープが終了し、GCの対象となり、関数のソートで適格になるためobjects = null、ここでは問題ではないと思いますそれらを追加または削除するときに NPE を取得しても意味がありません 。unwrappedCollections.sort(this.slaves, CMP_IDX_SLV);unwrapped = null;

NPE になるのは偶然だと思います。もう一度テストを実行すると、そのステートメントでも NPE になると思います。

Java ドキュメントを読む場合

参照先がファイナライズ可能になり、ファイナライズされてから再利用されることを妨げない弱参照オブジェクト。弱参照は、正規化マッピングを実装するために最もよく使用されます。
ある時点でガベージ コレクターが、オブジェクトが弱い到達可能性であると判断したとします。その時点で、そのオブジェクトへのすべての弱参照と、強参照と弱参照のチェーンを介してそのオブジェクトに到達できる他の弱到達可能オブジェクトへのすべての弱参照をアトミックにクリアします。同時に、以前は弱く到達可能だったすべてのオブジェクトがファイナライズ可能であると宣言します。同時に、または後で、参照キューに登録されている、新しくクリアされた弱参照をキューに入れます。

Listそのため、いくつかのオブジェクトからを構築したときにunwrap()マークされている可能性があり、作業中にいくつかが割り当てられている可能性がfinalizedあります。そして、Mattias Buelensが述べた点は完全に有効であり、コンパイラとの戦いでは常に負けます。Collection.sortWeakRefrencenull

私に同意する場合、これは JIT のバグですか?

いいえ、そうではありません。私はあなたに完全に同意しません。

comparatorで弱い参照を許可するように変更する考えがありますnull。あれについてどう思う?

NPE の 1 つの問題は解決すると思いますが、要件removes void weak references and ensures that weak references are not voided during subsequent sortは満たされていません。
むしろもう一度呼び出してみてくださいunwrap。これにより、NPE のウィンドウがほぼゼロになります。

List<T> unwrapped = unwrap();
unwrapped = unwrap(); //Again to eliminate the chances for NPE as now we would have 
           //already made strong refrences to all objects which have not been `null`
于 2013-12-28T13:36:06.617 に答える