Javaでのオブジェクト作成を避けるべきですか?


243

同僚から、Javaオブジェクトの作成は実行できる最も高価な操作であると言われました。したがって、できる限り少ないオブジェクトを作成することしかできません。

これは、オブジェクト指向プログラミングの目的をやや損なうようです。オブジェクトを作成していない場合、最適化のために1つの長いクラスCスタイルを記述しているだけですか?


39
「Javaオブジェクトの作成は、実行できる最も高価な操作です」。その主張のソースを共有する心?
松o

92
そして-何と比較して最も高価な操作ですか?piを900桁に計算するのと比較するか、intを増やすのと比較しますか?
ジェイソン

4
彼らはその特定のオブジェクト作成の特定の部分について話しているのでしょうか?AppleがtableViewCellsにキューを使用する方法を考えています。おそらく、特定のオブジェクトに関連するオーバーヘッドのために、同僚がいくつかのオブジェクトを作成して再利用することを提案していたのでしょうか?なぜ彼らがそのような主張をするのかを理解しようとしています。
タイラーデウィット

3
これは、私がプログラミングについて聞いた中で最も面白いことの1つです。)
Mert Akcakaya

22
算術も非常に高価です。計算を避ける必要があります。JVMの起動は非常に高価なので、JVMを起動しないでください:-)。
ジェームズアンダーソン

回答:


478

あなたの同僚は彼らが何について話しているのか分かりません。

あなたの最も高価な操作はそれらを聞いているでしょう。彼らは、10年以上前の情報(この回答が投稿された当初の時点)に誤った方向を向ける時間を無駄にし、ここに投稿して真実を調べるために時間を費やす必要がありました。

10年以上前に聞いたり読んだりしたものを無知に吐き出し、それ以上何も知らないことを願っています。私は彼らが疑わしいと言う他のことも考えますが、これはいずれにせよ最新の情報を保持している人なら誰でもよく知っている間違いです。

すべてがオブジェクトです(を除くprimitives

プリミティブ(int, long, doubleなど)以外はすべてJavaのオブジェクトです。Javaでのオブジェクトの作成を回避する方法はありません。

Javaでのメモリ割り当て戦略によるオブジェクト作成は、ほとんどの場合C ++よりも高速で、JVMの他のすべてと比較して実用的な目的のために「フリー」と見なすことができます

1990年代後半から2000年代初頭にかけてのJVM実装では、オブジェクトの実際の割り当てでパフォーマンスのオーバーヘッドが発生していました。これは、少なくとも2005年以来そうではありません。

-Xmsアプリケーションを正しく実行するために必要なすべてのメモリをサポートするように調整すると、GCを実行する必要がなくなり、最新のGC実装でほとんどのガベージをスイープする必要がなくなります。

とにかく赤いニシンである空き領域を最大化しようとはしませんが、ランタイムのパフォーマンスを最大化します。それは、JVMヒープが常にほぼ100%割り当てられていることを意味する場合は、そうする必要があります。とにかく、無料のJVMヒープメモリはそこに座っているだけではありません。

GCは便利な方法でメモリを解放してシステムの残りの部分に戻すという誤解がありますが、これは完全に間違っています!

JVMヒープは拡大も縮小もしないため、システムの残りの部分はJVMヒープの空きメモリによってプラスの影響を受けます。-Xms起動時に指定されたすべてを割り当てます。そのヒューリスティックは、JVMのインスタンスが完全に終了するまで、メモリをOSに実際に解放して他のOSプロセスと共有しないことです。-Xms=1GB -Xmx=1GB常に実際に作成されるオブジェクトの数に関係なく、1GBのRAMを割り当てます。ヒープメモリのパーセンテージを解放できるようにする設定がいくつかありますが、すべての実用的な目的のために、JVMはこれが発生するのに十分なメモリを解放することはできませんそのため、他のプロセスはこのメモリを再利用できません。そのため、システムの残りの部分も、JVMヒープが解放されても恩恵を受けません。このためのRFEは2006年11月29日「承認」されましたが、これまで何も行われていません。これは行動であり、権威者による懸念ではありません。

多くの小さな短命のオブジェクトを作成すると、JVMが長時間停止するという誤解がありますが、これも同様にfalseです

現在のGCアルゴリズムは、短命である多くの小さなオブジェクトを作成するために実際に最適化されています。これは、基本的にすべてのプログラムのJavaオブジェクトの99%のヒューリスティックです。オブジェクトプーリングを試みると、ほとんどの場合、実際にはJVMのパフォーマンスが低下します。

現在プーリングが必要なオブジェクトは、JVMの外部にある有限のリソースを参照するオブジェクトのみです。ソケット、ファイル、データベース接続など、再利用できます。通常のオブジェクトは、メモリの場所に直接アクセスできる言語と同じ意味ではプールできません。オブジェクトキャッシングは異なる概念であり、一部の人々が単純にプーリングと呼ぶ場合とそうでない場合があります。2つの概念は同じものではなく、混同すべきではありません。

最新のGCアルゴリズムは、スケジュールに従って割り当てを解除しないため、特定の世代で空きメモリが必要になると割り当てを解除するため、この問題はありません。ヒープが十分に大きい場合、一時停止を引き起こすほど長く割り当て解除は発生しません。

オブジェクト指向の動的言語は、計算依存テストで今日でもCに勝っています。


275
+1:「あなたの最も高価な操作はそれらを聞いているでしょう...」。しばらく聞いた中で最高です。
rjnilsson

21
@DeadMGは、累積GCオーバーヘッドがあっても、Java C ++よりも高速です(たとえば、ヒープの圧縮により、特定のデータ構造のキャッシュミスが最小限に抑えられます)。
SKロジック

13
@ SK-logic:GCは非決定的であるため、実際にそれを証明することはせいぜい非常に困難です。キャッシュミスを最小限に抑えるために、すべてのオブジェクトが別のインダイレクションでなければならない場合、キャッシュスペースを浪費し、実行時間を増やすことは困難です。ただし、オブジェクトプールやメモリアリーナのようなC ++で適切なアロケーターを使用するだけで、ガベージコレクターのパフォーマンスに簡単に匹敵する、または打ち負かすことができると私は主張します。たとえば_alloca、償却よりも高速に実行されるメモリアリーナクラスを作成できます。
DeadMG

33
オブジェクトの作成は、以前よりも安価になりました。しかし、無料ではありません。嘘をついているとあなたに話す人。そして、オブジェクト指向言語がCに勝つというリンクは、真に学習しようとしている人への誇張された反応です。
ジェイソン

17
このような答えが原因で、私たちは安っぽいコードになってしまいます。正しい答えは、Javaでオブジェクトを作成することは、Javaオブジェクトの作成と初期化の両方です。最初の部分は安価で、第二はでき非常に高価になります。newホットスポットでキーワードを使用する前に、コンストラクターで何が起こるかを常に確認する必要があります。Swingオブジェクトnew ImageIcon(Image)paint()メソッドで人々が使用するのを見てきましたが、これはかなり高価で、UI全体が非常に遅くなりました。だから、それはあなたが使用する前に考えて、黒と白の答えではありませんnewどこか。
qwertzguy

94

結論:オブジェクトを作成するショートカットを作成するために、デザインを妥協しないでください。不必要にオブジェクトを作成しないでください。賢明な場合は、(あらゆる種類の)冗長な操作を避けるように設計してください。

ほとんどの答えに反して-はい、オブジェクトの割り当てにはコストがかかります。低コストですが、不要なオブジェクトを作成しないでください。コード内の不要なものを避ける必要があるのと同じです。大きなオブジェクトグラフを使用すると、GCが遅くなり、実行時間が長くなる可能性があるため、メソッド呼び出しが増え、CPUキャッシュミスが発生し、RAMが少ない場合にプロセスがディスクにスワップされる可能性が高くなります。

これがエッジケースであると暴言を言う前に-最適化する前に、最大50行のデータを処理するために20MB以上のオブジェクトを作成したアプリケーションのプロファイルを作成しました。これは、1分間に100件のリクエストにスケールアップし、突然1分間に2GBのデータを作成するまで、テストでは問題ありません。20 reqs / secを実行する場合は、400MBのオブジェクトを作成してから破棄します。まともなサーバーの場合、20 reqs / secはごくわずかです。


7
私は例を追加することがあります。いくつかのケースでは、それは実際にコードを明確にするという点で違いはありませんが、パフォーマンスに多かれ少なかれ大きな違いを生むことができます:ストリームから読み込む場合、例えば、のようなものを使用することは珍しいことではありませんwhile(something) { byte[] buffer = new byte[10240]; ... readIntoBuffer(buffer); ...かもしれません例に比べて無駄が多いbyte[] buffer = new byte[10240]; while(something) { ... readIntoBuffer(buffer); ...
JimmyB

4
+1:不要なオブジェクトの作成(または削除後のクリーンアップ)は、明らかにコストがかかる場合があります。Javaの3Dグラフィックス/ OpenGLコードは、GCがフレームレートを破壊する可能性があるため、作成されるオブジェクトの数を最小限に抑えるために最適化が行われた場所の1つです。
レオ

1
うわー!50行のデータを処理するには20 MB以上ですか?クレイジーに聞こえます。いずれにせよ、それらのオブジェクトは長寿命ですか?それはGCにとって重要なケースだからです。あなたは、単に議論している一方、場合メモリ要件を、それがガベージコレクションやオブジェクトの作成効率とは無関係なのです...
アンドレス・F.

1
オブジェクトは短命です(一般的なケースでは0.5秒未満)。その量のガベージは依然としてパフォーマンスに影響します。
ジェイソン

2
実際に現実にしっかりと立ってくれてありがとう、思慮のないアーキテクチャの影響で生きる人は誰でも非常に関連することができます。
JMベッカー

60

実際、Java言語(または他のマネージ言語)が可能にするメモリ管理戦略により、オブジェクトの作成は、若い世代と呼ばれるメモリブロック内のポインタをインクリメントする以上のことはありません。空きメモリの検索を行う必要があるCよりもはるかに高速です。

コストの他の部分はオブジェクトの破壊ですが、Cと比較するのは困難です。コレクションのコストは長期保存されたオブジェクトの量に基づきますが、コレクションの頻度は作成されたオブジェクトの量に基づきます...最後に、Cスタイルのメモリ管理よりもはるかに高速です。


7
+1ガベージコレクタは「機能します」が、すべてのJavaプログラマは世代別ガベージコレクタについて学ぶ必要があります。
ベンザド

18
Javaの新しいバージョンはエスケープ分析を実行できます。つまり、スタック上のメソッドをエスケープしないオブジェクトにメモリを割り当てることができるため、クリーンアップは無料です。ガベージコレクタはこれらのオブジェクトを処理する必要がありません。 、メソッドのスタックフレームが巻き戻されると(メソッドが戻ると)自動的に破棄されます。
ジェスパー

4
次のステップエスケープ分析のためには、(例えば、純粋レジスタに小さなオブジェクトのメモリを「割り当て」であるPointオブジェクトが2つの汎用レジスタ内に収まることができます)。
ヨアヒムザウアー

6
@Joachim Sauer:これは、HotSpot VMの新しい実装で行われていることです。スカラー置換と呼ばれます。
-someguy

1
@someguy:少し前に次のこととしてそれについて読んだことがありますが、既に行われているかどうかを確認するためにフォローアップしませんでした。すでにこれを持っていると聞いて素晴らしいニュースです。
ヨアヒムザウアー

38

他のポスターは、Javaではオブジェクトの作成が非常に高速であり、通常のJavaアプリケーションでは通常、オブジェクトの作成について心配するべきではないことを正しく指摘しています。

非常に特殊な状況のカップルがあります。あるオブジェクトの作成を回避するために、良いアイデア。

  • あなたが書いているときは、レイテンシに敏感なアプリケーションをし、GCの一時停止を避けたいと思います。作成するオブジェクトが多いほど、GCが発生し、一時停止の可能性が高くなります。これは、ゲーム、一部のメディアアプリケーション、ロボット制御、高頻度取引などに関連する有効な考慮事項である可能性があります。解決策は、必要なすべてのオブジェクト/配列を事前に割り当てて再利用することです。Javolutionなど、この種の機能の提供に特化したライブラリがあります。しかし、おそらく、低レイテンシを本当に気にするなら、JavaやC#ではなくC / C ++ / assemblerを使用する必要があります:-)
  • ボックス化されたプリミティブ(Double、Integerなど)を避けることは、特定の状況で非常に有益なマイクロ最適化になります。ボックス化されていないプリミティブ(double、intなど)はオブジェクトごとのオーバーヘッドを回避するため、数値処理などのCPU集中型の作業がはるかに高速です。通常、Javaではプリミティブ配列のパフォーマンスが非常に高いため、他の種類のオブジェクト。
  • 拘束メモリ状況は、各オブジェクトのために作成(アクティブ)オブジェクトの数を最小限にしたい小さなオーバーヘッド(JVMの実装に応じて、典型的には8~16バイト)を搬送します。このような状況では、多数の小さなオブジェクトではなく、少数の大きなオブジェクトまたは配列を使用してデータを保存することをお勧めします。

3
エスケープ分析により、短命(制限付きライフ)オブジェクトをスタックに保管できることに注意してください。これらのオブジェクトは、無料で割り振り解除できますibm.com/developerworks/java/library/j-jtp09275/index.html
Richard Tingle

1
@Richard:素晴らしい点-エスケープ分析は非常に優れた最適化を提供します。ただし、信頼に注意する必要があります。すべてのJava実装およびすべての状況で発生することが保証されているわけではありません。そのため、多くの場合、確実にベンチマークする必要があります。
mikera

2
また、100%正しいエスケープ分析は停止問題に相当します。複雑な状況ではエスケープ分析に頼らないでください。少なくとも時々は間違った答えを返す可能性があります。
ジュール

最初と最後のポイントは、すぐに解放される小さなオブジェクトには適用されず、エデンで死にます(Cでのスタック割り当てを考えて、ほとんど無料です)。GC時間やメモリ割り当てには影響しません。Javaのほとんどのオブジェクト割り当てはこのカテゴリに分類されるため、基本的に無料です。2番目のポイントはまだ有効です。
ビルK

17

あなたの同僚が言っていることには真実の核があります。オブジェクトの作成に関する問題は、実際にはガベージコレクションであることをお勧めします。C ++では、プログラマはメモリの割り当て解除方法を正確に制御できます。このプログラムは、好きなだけ長い間、または短い間、ごみを蓄積することができます。さらに、C ++プログラムは、それを作成したスレッドとは異なるスレッドを使用して、クラッドを破棄できます。したがって、現在動作しているスレッドがクリーンアップするために停止する必要はありません。

対照的に、Java仮想マシン(JVM)は定期的にコードを停止して、未使用のメモリを再利用します。ほとんどのJava開発者はこの一時停止に気付くことはありません。これは通常、頻繁ではなく非常に短いためです。JVMの蓄積が多いほど、またはJVMの制約が大きいほど、これらの一時停止が頻繁に発生します。VisualVMなどのツールを使用して、このプロセスを視覚化できます。

Javaの最近のバージョンでは、ガベージコレクション(GC)アルゴリズムを調整できます。一般的な規則として、一時停止を短くしたいほど、仮想マシンのオーバーヘッドが高くなります(つまり、CPUとメモリがGCプロセスの調整に費やした)。

これはいつ問題になるでしょうか?一貫したサブミリ秒の応答率を気にするときはいつでも、GCを気にします。Javaで記述された自動取引システムは、一時停止を最小限に抑えるためにJVMを大幅に調整します。そうでなければJavaを作成する企業は、システムの応答性が常に高い場合にC ++を使用します。

記録のために、私は一般的にオブジェクトの回避を容認しません!デフォルトはオブジェクト指向プログラミングです。このアプローチは、GCが邪魔になった場合にのみ調整し、JVMを調整して一時停止時間が短くなった後にのみ調整してください。Javaパフォーマンスチューニングに関する優れた書籍は、Charlie HuntとBinu JohnによるJavaパフォーマンスです。


10
最新のJVMは、「世界を止める」よりも優れたガベージコレクションアルゴリズムをサポートしています。ガベージコレクションに費やされる償却時間は、malloc / freeの明示的な呼び出しに費やされる時間よりも短いことがよくあります。また、C ++メモリ管理は別のスレッドで実行されますか?

10
Oracleの新しいJavaバージョンはエスケープ分析を行うことができます。つまり、メソッドをエスケープしないオブジェクトはスタックに割り当てられ、それらを無料でクリーンアップできます。メソッドが返されると自動的に割り当てが解除されます。
ジェスパー

2
@ThorbjørnRavnAndersen:本当ですか?一時停止の少ない GC を本当に意味しますか、それとも「通常は並列ですが、時々小さなビットを一時停止する」GCを意味しますか?GCがプログラムを一時停止できず、同時にオブジェクトを同時に移動できないことを理解していません。文字通り、私には不可能だと思われます
...-Mehrdad

2
@ThorbjørnRavnAndersen:どうすれば「世界を止める」ことができますが、「JVMを一時停止しない」ことができますか?それは意味がありません
...-Mehrdad

2
@ThorbjørnRavnAndersen:いいえ、本当にありません。私はあなたが言っていることを理解していません。GCは時々プログラムを一時停止します。その場合、定義上、「一時停止」ではないか、プログラムを一時停止しません(したがって、「一時停止」ではありません)。これは、GCの動作中にプログラムが一時停止されていることを暗示しているように見えるため、「追いつくことができないときに世界を停止する」ステートメントに対応します。どちらが当てはまるのか(一時停止しないのか、そうでないのか)、そしてそれがどのように可能であるかを説明してもらえますか?
Mehrdad


9

GCは多くの短命オブジェクトに合わせて調整されます

それは、オブジェクトの割り当てを簡単に減らすことができるなら、

1つの例は、ループで文字列を構築することです、素朴な方法は

String str = "";
while(someCondition){
    //...
    str+= appendingString;
}

これにより、String+=操作で新しいオブジェクトが作成されます(さらにStringBuilder、新しい基になるchar配列)

これを次のように簡単に書き換えることができます。

StringBuilder strB = new StringBuilder();
while(someCondition){
    //...
    strB.append(appendingString);
}
String str = strB.toString();

このパターン(不変の結果とローカルで変更可能な中間値)は、他のものにも適用できます

それ以外は、ゴーストを追いかけるのではなく、プロファイラーを引き上げて本当のボトルネックを見つける必要があります


この最大の利点StringBuilderアプローチがあり、プリサイズStringBuilderので、それをしなければならないことを再配分となる配列StringBuilder(int)コンストラクタを。これにより、割り当てではなく単一の割り当てになり1+Nます。

2
@JarrodRobersonのStringBuilderは、少なくとも2倍の電流容量または他の言葉で容量のみログ(n)の割り当てのために指数関数的に成長するであろう
フリークラチェット

6

Joshua Bloch(Javaプラットフォームクリエーターの1人)は2001年に彼の著書Effective Javaに次のように書いています

独自のオブジェクトプールを維持してオブジェクトの作成を回避することは、プール内のオブジェクトが極端に重い場合を除いて、悪い考えです。オブジェクトプールを正当化するオブジェクトの典型的な例は、データベース接続です。接続を確立するコストは十分に高いため、これらのオブジェクトを再利用するのは理にかなっています。ただし、一般的に、独自のオブジェクトプールを維持すると、コードが乱雑になり、メモリフットプリントが増加し、パフォーマンスが低下します。最新のJVM実装には、軽量オブジェクトでこのようなオブジェクトプールを簡単に上回るガベージコレクターが高度に最適化されています。


1
ネットワーク接続のようなものであっても、重要なのは、接続に関連付けられたGCに割り当てられたオブジェクトを維持するのではなく、GC管理の外に存在する接続のセットを維持することです。オブジェクトをプールすること自体が役立つ場合があります。それらのほとんどは、同じオブジェクトへの参照のペアが、同一ではあるが異なるオブジェクトへの参照のペアと意味的に同等である場合があるが、それでもいくつかの利点がある場合に由来します。例えば、同じ50-千文字の文字列に2つの参照が一致するかどうかは確認することができる...
supercat

2
...その長さの2つの異なるが同一の文字列への参照よりもはるかに高速です。
supercat 14

5

これは本当に特定のアプリケーションに依存するため、一般的に言うのは本当に難しいです。ただし、オブジェクトの作成が実際にアプリケーションのパフォーマンスのボトルネックになっている場合、私は非常に驚くでしょう。それらが遅い場合でも、コードスタイルの利点はおそらくパフォーマンスよりも重要です(実際にユーザーが気付かない限り)。

いずれの場合でも、推測する代わりに実際のパフォーマンスのボトルネックを決定するためにコードをプロファイルするまで、これらのことについて心配することを始めるべきではありません。それまでは、パフォーマンスではなく、コードを読みやすくするために最善のことを行う必要があります。


Javaの初期のバージョンでは、ガベージコレクターが破棄されたオブジェクトをクリーンアップするときにかなりのコストが発生しました。Javaの最近のバージョンではGCオプションが大幅に強化されているため、オブジェクトの作成が問題になることはほとんどありません。通常、Webシステムは、ページの読み込みの一部としてアプリケーションサーバー上で本当に複雑なものを計算しない限り、外部システムへのIO呼び出しによって制限されます。
グレッグ12年

3

あなたの同僚は、不必要なオブジェクト作成の観点から言ったに違いないと思います。同じオブジェクトを頻繁に作成する場合は、そのオブジェクトを共有することをお勧めします。オブジェクトの作成が複雑で、より多くのメモリを必要とする場合でも、そのオブジェクトのクローンを作成し、その複雑なオブジェクト作成プロセスの作成を避けることができます(ただし、要件によって異なります)。「オブジェクトの作成には費用がかかります」という文は文脈に沿って解釈する必要があると思います。

JVMのメモリ要件に関する限り、Java 8を待ちます。-Xmxを指定する必要さえありません。メタスペースの設定がJVMのメモリの必要性を処理し、自動的に成長します。


人々が答えを投票する間もコメントを入れると、非常に建設的です。結局のところ、私たちは皆知識を共有するためにここにいるのであり、適切な理由なしに単に判断を下すだけでは何の目的にもなりません。
AKS

1
スタック交換には、その回答にコメントが投稿されたときに、任意の回答に賛成票を投じたユーザーに通知するメカニズムが必要です。
AKS

1

クラスの作成には、メモリの割り当て以上のものがあります。初期化もあります。なぜその部分がすべての答えでカバーされないのか分かりません。通常のクラスにはいくつかの変数が含まれており、何らかの形式の初期化を行いますが、それは無料ではありません。クラスが何であるかに応じて、ファイルを読み取るか、他の多くの低速操作を実行します。

したがって、クラスコンストラクターが無料かどうかを判断する前に、クラスコンストラクターが何を行うかを検討してください。


2
適切に設計されたクラスは、その理由だけで、コンストラクタで重い負荷をかけるべきではありません。たとえば、ファイル読み取りクラスは、起動時にターゲットファイルが存在することを確認し、ファイルからのデータを必要とする最初のメソッド呼び出しまで実際のファイル操作を延期するだけで、インスタンス化のコストを削減できます。
GordonM

2
追加コストが「if(firstTime)」に移動した場合、ループでクラスを再作成するよりも、クラスを再利用するよりも費用がかかります。
アレックス

私は同様の答えを投稿しようとしていたが、これは正しい答えだと思う。多くの人々は、Javaオブジェクトの作成が安価であるという言葉に目をくらまされており、多くの場合、コンストラクターやさらなる初期化が安くはならないことを認識していません。たとえば、SwingのImageIconクラスは、プリロードされたImageオブジェクトを渡しても、コンストラクターはかなり高価です。そして、@ GordonMには同意しません。JDKの多くのクラスが、コンストラクターでinitの大部分を実行します。これにより、コードがよりスリムになり、設計が改善されると思います。
qwertzguy

1

JavaのGCは、実際には大量のオブジェクトを「バースト」方式で迅速に作成するという点で非常に最適化されています。私が理解できることから、彼らは「エデン空間」と呼ばれるメモリ空間にその種の「バーストサイクル」のためにシーケンシャルアロケーター(可変サイズのリクエストのための最速かつ最も簡単なO(1)アロケーター)を使用し、オブジェクトが持続する場合のみGCサイクルの後、GCが1つずつ収集できる場所に移動します。

とはいえ、パフォーマンスニーズが十分に重要になった場合(実際のユーザーエンドの要件で測定した場合)、オブジェクトにはオーバーヘッドがかかりますが、作成/割り当てに関してはあまり考えません。参照の局所性と、リフレクションやダイナミックディスパッチなどの概念をサポートするために必要なJavaのすべてのオブジェクトの追加サイズとの関係があります(多くのFloat場合float、64ビットではアライメント要件が4倍以上であり、 array of Floatは、私が理解しているものから連続して格納されるとは限りません)。

Javaで開発した最も目を引くものの1つは、私の分野(VFX)でヘビー級の競争相手であると考えさせたものです(インタラクティブなマルチスレッド標準パストレーサー(放射キャッシュ、BDPT、MLSなどを使用しません) CPUはリアルタイムのプレビューを提供し、ノイズのない画像にかなり迅速に収束します。私はC ++の専門家と仕事をして、そのようなことに専念してきました。

しかし、私はソースコードをじっと見つめましたが、それは些細なコストで多くのオブジェクトを使用していましたが、パストレーサーの最も重要な部分(BVHおよび三角形とマテリアル)は、プリミティブタイプの大きな配列を優先してオブジェクトを非常に明確かつ意図的に回避しました(ほとんどfloat[]int[])、それははるかに少ないメモリを使用floatし、配列内のある場所から次の場所に到達するための空間的局所性を保証しました。著者が好きなボックス化されたタイプを使用した場合、Floatそこでは、パフォーマンスにかなりのコストがかかります。しかし、私たちはそのエンジンの最も絶対に重要な部分について話しているので、開発者がどれだけ巧みに最適化したかを考えて、彼はそれを測定し、その最適化を非常に慎重に適用しました。彼の印象的なリアルタイムパストレーサーの些細なコスト。

同僚から、Javaオブジェクトの作成は実行できる最も高価な操作であると言われました。したがって、できる限り少ないオブジェクトを作成することしかできません。

私のようにパフォーマンスが重視される分野であっても、重要ではない場所で自分自身を縛り付けると、効率的な製品を書くことはできません。最もパフォーマンスが重要な分野では生産性に対する要求がさらに高くなる可能性があると主張することもあります。なぜなら、そうでない時間に無駄をかけないことで、本当に重要なホットスポットを調整するために余分な時間が必要になるからです。上記のパストレーサーの例と同様に、著者は巧妙かつ慎重にこのような最適化を、本当に重要で、おそらく測定後に後知恵のある場所にのみ適用し、それでも他のどこでも幸福にオブジェクトを使用しました。


1
最初の段落は正しい軌道に乗っています。エデンと若いスペースは、約を持っているコピーコレクターを使用しています。死んだオブジェクトのコストは0です。このプレゼンテーションを強くお勧めます。ちなみに、この質問は2012年のものであることに気付いていますか?
ジミージェームズ

@JimmyJames退屈して、古い質問も含めて質問をふるいにかけるのが好きです。人々が私のネクロマンシーを気にしないことを願っています!:-D
ドラゴンエナジー

@JimmyJamesボックス型に追加のメモリ要件があり、配列内で連続していることが保証されていないということはもはやありませんか?Javaではオブジェクトは安価であると思う傾向がありますが、比較的高価になる可能性があるのはfloat[]vsのようなものFloat[]です。
ドラゴンエナジー

1
私が最初にここに投稿し始めたとき、私は同じようにしました。古い質問への回答がほとんど注目されない場合でも、驚かないでください。
ジミージェームズ

1
ボックス化された型は、プリミティブよりも多くのスペースを使用すると想定されるべきだと確信しています。その周りに潜在的に最適化がありますが、私は一般的に、あなたが説明したとおりだと思います。(上記のプレゼンテーションの)Gil Teneは、構造体の利点の一部を提供するがオブジェクトを使用する特別な種類のコレクションを追加する提案について別の話をしています。これは興味深いアイデアです。JSRのステータスはわかりません。コストの大部分は時間によるもので、これはあなたがほのめかしているものです。オブジェクトを「エスケープ」させないようにすることができれば、スタックを割り当てることさえでき、ヒープに触れることはありません。
ジミージェームズ

0

人々が言っ​​たように、オブジェクトの作成はJavaで大きなコストではありません(ただし、追加などの最も単純な操作よりも大きいと思います)。

それはまだ費用がかかり、可能な限り多くのオブジェクトを廃棄しようとしていることに気付くことがあります。しかし、プロファイリングがこれが問題であることを示して初めてです。

このトピックに関する優れたプレゼンテーションは次のとおりです。https//www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf


0

これに関して簡単なマイクロベンチマークを行い、githubで完全なソースを提供しました。私の結論は、オブジェクトの作成に費用がかかるかどうかは問題ではありませんが、GCが処理を行うという概念でオブジェクトを作成し続けると、アプリケーションがGCプロセスをより早くトリガーするようになります。GCは非常に高価なプロセスであり、可能な限り避けることをお勧めします。


これは、以前の15の回答で作成および説明されたポイントに対して実質的な何かを提供するようには見えません。2年以上前に尋ねられ、非常に徹底的な答えを
-gnat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.