-3

次のコードでは、ループ内で複素数をある角度だけ回転させ、結果の数値が最初の数値と同じであることを確認します。

public class Complex {
    private float r, i;
    ...
    public Complex(Complex other) {
        r = other.r;
        i = other.i;
    }

}

Complex z1 = new Complex(..);
Complex z1_save = new Complex(z1);
Complex z2 = new Complex();
Complex k = new Complex();
k.set_to_first_root_of_unity(8);
int n = 64;
while(n-- != 0) {
    z1.multiply(k, z2);
    z1 = new Complex(z2); // Line Y
}
Assert.assertEquals(true, z1.equals(z1_save));

public Complex(Complex other)Javaではなくコンストラクタを使用してLine Yを記述しclone()、64個のオブジェクトがガベージコレクションされないことを確認する方法はありますか?

更新: 対話型アプリケーションのコンテキストを参照せずに、単純化した方法でこの質問をすることは不可能のようです。現在の質問 (assylias の) に対する最良の答えは、90% の確率でオブジェクトの作成とガベージ コレクションについて心配する必要はないということです。再描画中は、常に 100% 心配する必要があります。私はここで質問を言い直しました。

4

5 に答える 5

2

不必要に 64 回の GC の非効率性が心配です。

それは不必要な心配です。オブジェクトが若い世代 (そのスコープを考慮する) にある場合、GC は無料になります (0 コストのように)。

GC が若い世代で実行される場合、GC はライブ オブジェクトのみを通過するため (GC の対象となるオブジェクトはアクセスされません)、GC 時間はライブ オブジェクトのみの関数になります。

古い世代の場合は話が異なりますが、ローカル オブジェクトはその段階に到達しません。

参照 - Brian Goetz、強調鉱山:

解放についてはどうですか?

しかし、割り当てはメモリ管理の半分にすぎません。割り当て解除は残りの半分です。ほとんどのオブジェクトの場合、直接のガベージ コレクションのコストは -- ゼロです。これは、コピー コレクターがデッド オブジェクトを参照またはコピーする必要がなく、ライブ オブジェクトのみを参照するためです。そのため、割り当て直後にガベージになるオブジェクトは、コレクション サイクルに負荷をかけません。

典型的なオブジェクト指向プログラムのオブジェクトの大部分 (さまざまな調査によると 92 ~ 98%) は「若くして死ぬ」ことが判明しました。つまり、オブジェクトは、割り当てられた直後、多くの場合、次のガベージ コレクションの前にガベージになります。(このプロパティは世代仮説と呼ばれ、経験的にテストされ、多くのオブジェクト指向言語で正しいことがわかっています。)したがって、割り当てが高速であるだけでなく、ほとんどのオブジェクトでは、割り当て解除は無料です。

于 2013-01-23T23:27:47.040 に答える
1

次の場合を除いて、ガベージコレクションに注意を払う理由はまったくありませ

  • ユーザー(多分あなた)は、アプリケーションのパフォーマンスの問題を認識します。

  • アプリケーションのプロファイリングは、ガベージコレクションが認識されたパフォーマンスの問題の原因であることを示しています。

これらの条件の両方が欠けている:ガベージコレクションを無視します。

これは、一般的なJavaのパフォーマンスチューニングに当てはまります。本当の理由があることが証明されない限り、それをしないでください。

于 2013-01-24T00:41:04.993 に答える
1

10 (またはそれくらい) のフィールドを持つオブジェクトに対してコンストラクターを 64 回実行することは、携帯電話のようなデバイスであっても大したことではありません。

あなたの仕事が何であるかは明らかではありません。

コンストラクターを何度も呼び出して同一のオブジェクトを作成しすぎることを本当に懸念している場合は、Flightweight パターンを使用してみてください。

于 2013-01-23T23:24:13.517 に答える
1

あなたの質問(およびコメント)は少し混乱しています...しかし、それはあなたの英語力の問題かもしれません. ですから、あなたの言いたいことは理解できたと思います。また、あなたの例が「機能する」と仮定しています...現在は機能していません。

簡単に言えば、オブジェクトを変更可能にすることで、オブジェクトのチャーン (つまり、「一時的な」オブジェクトの作成と解放) を減らすことができるということですComplex。通常、これを行うには、オブジェクトの状態を変更できるセッター操作を追加します。しかし、それはあなたのComplexクラスを正しく使用することをより困難にする効果があります。例えば:

    public static final ZERO = new Complex(0, 0);

    // somewhere else

    Complex counter = ZERO;
    while (counter.lessThan(10)) {
        // ....
        counter.setRealPart(counter.getRealPart() + 1);  // Ooops!!
    }

...そしてそのようなバグがたくさんあります。

次に、これが実際にガベージ コレクションのオーバーヘッドを削減するかどうか、およびどれだけ削減できるかという問題があります。

@assylias が指摘しているように、作成されて次の GC サイクルで再利用される一時オブジェクトのコストは非常に低くなります。高価なオブジェクトは、ガベージにならないオブジェクトです。また、通常の環境で実行される通常のプログラムの場合、一時オブジェクトを作成する 方が実際には全体的に効率的である可能性は十分にあります。

次に、最新の HotSpot JVM が「エスケープ分析」と呼ばれる処理を実行できるという問題があります。これは、(機能する場合) 特定の一時オブジェクトがその作成スコープの外に表示されることは決してないため、その必要がないことを判断できます。ヒープにまったく割り当てられません。その最適化を適用できる場合、「オブジェクト チャーン」の懸念は解消されます。

ただし、GC を実行すると、「リアルタイム」のパフォーマンスが低下する可能性があります。たとえば、ゲームのプログラミングでは、ゲームがほんの一瞬フリーズした場合にユーザーが気付く場合があります。そのような場合、コードを「チューニング」してオブジェクトのチャーンを減らすことを検討する価値があります。しかし、他にも可能なアプローチがあります...一時停止の少ないガベージコレクターを使用するなど...プラットフォームで使用できる場合。


@assylias のコメントは、別の重要な点です。時期尚早の最適化に注意してください。オブジェクトの使用法に関するあなたの直感Complexと、結果として生じるオブジェクト チャーンは、非常に間違っている可能性があります。すべてが同じであれば、アプリケーションのプロファイリングを行い、次のことを判断するまで、最適化作業を遅らせるのが最善です。

  • 調整する必要があり、
  • プロファイリングの証拠は、Complexクラスが重大なパフォーマンスのボトルネックであることを示しています。
于 2013-01-23T23:59:40.510 に答える
-1

GC に関して効率的になりたい場合は、new の使用を最小限に抑えます。

したがって、あなたの例では、「Line Y」の変数を再利用し、フィールドに新しい値を設定するだけです。何かのようなもの:

while(n-- != 0) {
    z1.multiply(k, z2);
    z1.setValue(z2); // Line Y
}

z1.setValue(X) は、コンストラクター new Complex(x) と同じ方法でオブジェクトの状態を設定します。


編集:なぜこれが反対票を投じているのですか? 私は、new の使用を最小限に抑えることによって GC のコストを削減するという上記の声明を支持します。はい、ほとんどの状況で GC は問題ではないことに同意します。しかし、コードが頻繁に GC を呼び出す場合、おそらくコードがループ内で多くの時間を費やしているため (CPU 負荷の高いアルゴリズムなど)、オブジェクトを再利用することをお勧めします。 .

于 2013-01-23T23:10:33.580 に答える