メモリアーキテクチャ:ErlangとJava

非常に興味深い記事「Erlang VMのメモリ管理戦略」を読みました。 Jesper Wilhelmsonによる論文として書かれました。 Erlangのメモリ管理とOracleのJava VMの違いを議論するのは良いことだと思いました。



Erlangを聞いたことがない人のための非常に簡単な紹介:非同期メッセージングを並行性の基礎として使用する関数型言語です。 メッセージ転送はコピーセマンティクスを使用します。これにより、複数のマシンで実行されている複数のErlang VMの配布がプログラマーに対して基本的に透過的になります。



ErlangとJavaは、どちらも仮想マシンを使用してハードウェアレイヤーから抽象化するという意味で似ています。 両方の言語は、マシンに依存しないバイトコードを使用します。 どちらもガベージコレクションを備えたランタイムシステムであり、プログラマが手動のメモリ管理から解放されます。



Erlangのストリームのオーバーヘッド(元々オーバーヘッド)は非常に低いです。 Erlangストリームには約512バイトが必要なようです。 Javaスレッドは通常、約512キロバイトを必要とし、これは約1000倍です。 非同期で動作する複数のスレッドを備えたシステムは、プログラマーが十分に検討する必要があります。 典型的なErlangシステムは、数千または数万のスレッドを保持します。 同時に、Javaで行うスレッドプールやエグゼキューターにだまされません。



Erlangを少し使ってみたところ、関数型言語と実際のアプリケーションを作成できる言語とのかなり良い妥協点であることがわかりました。 (私はこのフレーズに対して鋭い批判に直面することを知っています)。 信頼できる分散エラー処理は嬉しい驚きであり、あらゆる種類のネットワークサーバーの作成は実際には非常に簡単です。 Webサーバーへの自動化されたアプローチにより、エラーのロールバックは非常に自然になります。



しかし、この投稿はErlangプログラミングモデルに関するものではありません。 彼は、Erlang VMがメモリでどのように機能するかについて説明しています。



Java仮想マシンは、プログラマが一般的なヒープトポロジと呼ぶErlangを使用します。 すべてのスレッドで使用される1つの大きなヒープがあります。 ほとんどのメモリはこのヒープに割り当てられます。 ヒープに加えて、JVMはコードキャッシュや永続的な生成などの特殊なデータ領域を使用します。 また、すべてのスレッド間で共有されます。



対照的に、Erlangはプライベートヒープトポロジを使用します。 各スレッドには独自の小さなヒープがあり、スレッドとそのスタックで使用されるすべてのデータが含まれています。 すべてのストリームデータはローカルヒープにあります。 スレッドが作成されるときに予約されます。 スレッドが破棄されると、ヒープ全体が単純に空きメモリプールに戻ります。



プライベートヒープに加えて、いわゆるバイナリヒープとメッセージヒープはすべてのスレッドで使用できます。 これらは特殊なヒープです。 入力ファイルやネットワークバッファなど、ストリーム間で共有できる任意のデータの大きな領域を割り当てるには、バイナリヒープが必要です。



メッセージヒープは、メッセージで使用されるデータ用です。 メッセージはプロセス間でも配信されます。 メッセージは、送信ストリームから宛先ストリームにポインターをコピーすることにより、ストリーム間で転送されます。 メッセージデータは、メッセージのヒープに格納されます。



私はアーランの記憶モデルに感銘を受けました。 Javaのシングルヒープモデルよりもはるかにスケーラブルなようです。 言語のセマンティクスとErlangメモリモデルは完全に組み合わされています。



たとえば、ヒープが閉じられているという単純な事実により、デッドロックの出現が排除され、したがって、デッドロックのチェックが排除されます。



Erlang VMの最新バージョンは、さらに一歩前進します-複数のスケジューラーを持つ機能。 正確には、物理​​プロセッサごとに1つのスケジューラ。 また、ロックのクラス全体をチェックする必要もなくなります。 スケジューラがアイドル状態のとき、別のスケジューラからいくつかのプロセスを受信する場合があります。



JavaはErlangから学ぶべきことがたくさんあります。 ただし、大規模なErlangシステムで作業するときに見落としているJavaの良い点がいくつかあります。



Erlang VMは、ストリームが大量のデータを蓄積すると、ヒープを再配布します。 ただし、再配布アルゴリズムでは、何らかの理由で、ヒープサイズが急速に増加します。 重い負荷の下で、Erlang VMが16 GBのRAMを数分で消費するのを見ました。 十分なメモリ要件があるように、各リリースを負荷テストで慎重にテストする必要があります。



Erlang VMにはメモリの増加を抑えるメカニズムはありません。 仮想マシンは、システムがスワップを実行し、仮想メモリを使い果たすほど多くのメモリを喜んで割り当てます。 これにより、KVMコンソールからアクセスした場合でも、マシンがフリーズする可能性があります。 過去には、再び車にアクセスするために車を過負荷にしなければなりませんでした。



Erlangのキューベースのプログラミングモデルを使用すると、コードを非常に喜んで作成できますが、一方で、本番環境ではアキレス腱です。 Erlangの各キューは無制限です。 仮想マシンは、例外をスローしたり、キュー内のメッセージ数を制限したりしません。 プロセスがエラーのためにメッセージの処理を停止したり、送信されたメッセージの流れに追いついていないことがあります。 この場合、Erlangは、VMが強制終了されるか、マシンがロックされるまで、このプロセスのメッセージキューが拡大することを許可します。



これは、実稼働環境で「大規模な」Erlang VMを実行する場合、使用するメモリが多すぎる場合にプロセスを強制終了するオペレーティングシステムレベルのチェックが必要であることを意味します。



したがって、Erlangのプライベートヒープメモリモデルは非常に強力なツールになると考えています。 実行時にロックメカニズムのクラス全体が排除されるため、Javaよりも優れた拡張性が得られます。 一方、Javaの厳しいメモリ制限は、システムが完全に機能している場合、またはDDoSの下にある場合にメリットをもたらします。



さて、そして最後に:



Erlang VMには、プライベートヒープトポロジの使用から共有ヒープトポロジの使用に移行できるコマンドラインオプションがあります。



ErlangとJavaが好きです。 開発者にとって共通点が少なすぎるため、比較するのは困難です。 ただし、一般的に、ほとんどのシステムでは、Javaを使用したいと思います。 彼女はさまざまなツールを最大限にサポートしており、利用可能なライブラリの数は圧倒的です。 スレッド指向のメッセージングシステムが必要な場合は、Erlangを選択します。 これが、Erlangプログラミングモデルが本当に素晴らしいところです。



参照:

JCGパートナーであるJava-MonitorのキースヤンコスターのErlangメモリアーキテクチャとJavaメモリアーキテクチャ



ハッピーコーディング! 共有することを忘れないでください!

バイロン



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=

オリジナルへのリンクには、興味深い(および反証する)コメントが含まれています。



All Articles