質問

私の目標は、Javaで割り当てられた配列が連続した物理メモリに割り当てられるようにすることです。私が遭遇した問題は、本当に大きな配列を割り当てない限り、配列が割り当てられているページが物理メモリで連続していない傾向があるということです。

私の質問:

  • 本当に大きな配列が保証する理由 物理メモリ内で連続するページ?
  • 配列を物理メモリ全体に確実に割り当てる方法はありますか。配列を本当に大きくする必要はありませんか?
  • キャッシュヒット/キャッシュミスを測定せずに、Javaオブジェクト/配列が存在するページまたは物理アドレスをどのように確認できますか?

Javaでこれを行う理由を尋ねる回答を探していません。 Cは「私の問題を解決する」と理解し、Javaの基本的な性質に反することを理解しています。それにもかかわらず、私はこれを行う正当な理由があります。

答えが常に機能することを保証する必要はありません。私はほとんどの場合に役立つ答えを探しています。合理的なJavaプログラマーが書くことのできない独創的ですぐに使える答えのための追加ポイント。プラットフォーム固有(x86 32ビット64ビット)でもかまいません。

役に立ちましたか?

解決

ガベージコレクターが(論理)メモリ内でオブジェクトを移動することを考えると、あなたは運が悪くなると思います。

できる最善の方法は、 ByteBuffer.allocateDirect 。 GCによって(通常)(論理)メモリ内を移動することはありませんが、物理メモリ内で移動したり、ディスクにページアウトすることもあります。より良い保証が必要な場合は、OSにアクセスする必要があります。

ページサイズをヒープと同じ大きさに設定できる場合、すべての配列は必然的に物理的に連続する(またはスワップアウトされる)と言いました。

他のヒント

いいえ。物理的に連続したメモリには、OSとの直接の対話が必要です。 JVMに含まれるほとんどのアプリケーションは、実質的に連続したアドレスのみを取得します。また、JVMはOSから得られないものを提供できません。

さらに、なぜあなたはそれが欲しいのでしょうか? DMA転送を設定している場合は、とにかくJava以外のテクニックを使用している可能性があります。

ビットの背景:

最新のPCの物理メモリは、交換可能なDIMMモジュールでは通常、柔軟な量です。その各バイトには物理アドレスがあるため、ブート中のオペレーティングシステムは、使用可能な物理アドレスを決定します。これらのアドレスを直接使用しないことで、アプリケーションの方が優れていることがわかります。代わりに、最新のすべてのCPU(およびそのキャッシュ)は仮想アドレスを使用します。物理アドレスへのマッピングテーブルがありますが、これは完全である必要はありません-物理アドレスにマッピングされていない仮想アドレスを使用することにより、ディスクへのスワップが可能になります。プロセスごとに1つのテーブルがあり、マッピングが不完全なため、別のレベルの柔軟性が得られます。プロセスAに物理アドレスXにマップする仮想アドレスがあるが、プロセスBにはない場合、プロセスBが物理アドレスXに書き込む方法はなく、そのメモリはプロセスAに排他的であると考えることができます。これを安全にするために、OSはマッピングテーブルへのアクセスを保護する必要がありますが、最新のすべてのOSは保護します。

マッピングテーブルはページレベルで機能します。ページまたは物理アドレスの連続したサブセットは、仮想アドレスの連続したサブセットにマッピングされます。オーバーヘッドと粒度のトレードオフにより、4KBページが一般的なページサイズになりました。ただし、各ページには独自のマッピングがあるため、そのページサイズを超える連続性を想定することはできません。特に、ページが物理メモリから追い出され、ディスクにスワップされ、復元されると、新しい物理メモリアドレスに到達する可能性が非常に高くなります。仮想アドレスは変更されず、OS管理のマッピングテーブルのみが変更されるため、プログラムは認識しません。

特定のJVMをだまして目的の操作を実行する方法もありますが、これらはおそらく壊れやすく、複雑であり、JVM、そのバージョン、実行するOSなどに非常に固有のものである可能性が高いでしょう。 。

だからあなたの問題についてもっと知ることなくして、誰も助けてくれるとは思わない。 確かに、一般にJavaで、多くても特定のJVMでそれを行う方法はありません。

代替案を提案するには:

本当に連続したメモリにデータを保存する必要がある場合、小さなCライブラリでデータを保存し、JNI経由で呼び出してみませんか?

見たとおり。理由をまだ説明していない

  • プリミティブ配列はメモリ内で連続していないこと。仮想メモリ内でそれらが連続しない理由はわかりません。 (c.f.オブジェクトの配列は、メモリ内でオブジェクトが連続していない可能性があります)
  • 物理メモリ(RAM、つまりランダムアクセスメモリ)で連続していないアレイは、パフォーマンスに大きな違いがあります。例えばアプリケーションのパフォーマンスの測定可能な違い。

表示されるのは、Cでこれを行うことに慣れているため、実際に配列を割り当てる低レベルの方法を探していることです。パフォーマンスはこれを行う必要があるという主張です。

BTW:getDouble()/ putDouble()を使用したByteBuffer.allocateDirect()へのアクセスは、double []を使用すると前者がJNI呼び出しを含み、後者がまったく呼び出しを行わないように最適化できるため、遅くなる可能性があります。

これが使用される理由は、JavaスペースとCスペースの間でデータを交換するためです。例えばNIO呼び出し。読み取り/書き込みが最小限に抑えられている場合にのみ、パフォーマンスが向上します。それ以外の場合は、Javaスペースで何かを使用する方が良いでしょう。

i.e。あなたが何をしているのかが明確でなく、なぜそれをしているのでなければ、あなたは気分が良くなるかもしれない解決策になりますが、実際は単純な解決策よりも複雑でパフォーマンスが悪いです。

注:この回答は、System.identityHashCodeについて説明している関連質問への回答です。 ()およびオブジェクトのメモリアドレスの識別。一番下の行は、デフォルトの配列hashCode()実装を使用して、配列の元のメモリアドレスを識別することができるということです(int / 32ビットに収める必要があります)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top