JVM メモリには何がありますか?
JVM のメモリ使用量を示すグラフを見てみましょう。

このグラフでは、512 MBのJavaヒープスペースを持つアプリケーションが示されています。これは、主に Mendix アプリケーション自体。マイクロフローでオブジェクトを取得する場合、データベースから読み取られたオブジェクトはここでメモリに保持されます。
その Mendix ランタイムはこのスペースを使用して、ログインしたセッションのJavaオブジェクト、データベースからの生データをマイクロフロー内で使用できるオブジェクトに変換する中間オブジェクト、またはWebブラウザのデータグリッドに表示する必要があるデータの場合はワイヤ上で直接転送できるオブジェクトを保存します。マイクロフロー自体もここでオブジェクトであることをご存知でしたか? Mendix ランタイムはインタープリターであり、モデル化されたアプリケーションのコピーをメモリに保存します。
このメモリ空間のさまざまな部分は、JVMガベージコレクタによって管理されます。( JVM ヒープのドキュメント)
前に示した例は、実際にはまったく使用されていないが、おそらく何らかのスケジュールされたイベントがあり、そのイベントによって多数のオブジェクトが作成され、その後すぐにガベージ コレクションされる可能性があるアプリケーションの例です。
JVM だけではありません...
さて、このJavaメモリはオペレーティングシステム自体のシステムメモリ内に収まる必要があります。 Mendix クラウドでは、デプロイメント ポータルの監視部分でこれらのグラフを表示できます。
これはオペレーティングシステムのメモリの実際の使用状況を示すグラフです。これはいわゆるappnodeで、単一の環境のアプリケーションプロセスを実行するために専用に使用されます。 Mendix アプリケーション (つまり、テスト環境、受け入れ環境、または本番環境のいずれか)。

かなり正確ですね。約500MBが使用されているので、これは上で見たJavaヒープに違いありません。データベースは別の仮想マシンで実行されているため、データベースの使用量はここでは表示されません。 Mendix Java プロセスに適合するように 1024 MB のメモリを備えた Linux 仮想マシンをプロビジョニングしました。
待って、何?
さて、別の例を見てみましょう。


ちょっと待ってください…オペレーティングシステムで、本来900MBしか使用できないはずのメモリが512MB以上使用されているのはなぜでしょうか? Mendix 使用されていないメモリを活用するために、アプリケーションと並行して他のプロセスを秘密裏に実行していますか?
いいえ、そうではありません。本当に。🙂 そうですね... アプリケーション自体の他に、常に実行されている追加のプロセスがいくつかあります。たとえば、2 つの監視エージェントがあり、1 つはトレンド システムにデータを提供する (これらのグラフを作成するため) もので、もう 1 つはアラート システムにデータを提供するものです。また、デプロイメント ポータルから停止ボタンまたは開始ボタンを押して信号を受信すると、アプリケーションを停止および開始できるプロセスがあります。
しかし、それらはすべて、最初に示した例にも存在していました。では、ここでは何が起こっているのでしょうか…?
サーバー上の各プロセスが占有するメモリ量を表示できる ps コマンドの出力を見てみましょう。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxxx 19137 1.8 84.7 1248796 864696 ? Sl 2014 1177:33 java -Dfile.encoding=UTF-8 -XX:MaxPermSize=128M -Xmx512M -Xms512M -Djava.io.tmp...
はい、実際に 864696 KB のメモリを使用しているのは Java プロセスです。
なぜ迷惑?
なぜこれについて気にする必要があるのでしょうか? 結局のところ、この 1024 MB の Java プロセスが何らかの魔法によって 512 MB に増加したとしても、プロセスは使用可能な 844 MB のメモリ内に収まります。
実は、この種の動作は、時々起動されるサーバー上で他のプログラムの実行を妨げるため、いくつかの問題を引き起こします。
リリースとセキュリティアップデートを実施します…
At Mendix弊社では、定期的に、そしておそらく想像するよりもずっと頻繁に、ホスティング プラットフォームに変更を加えています。毎週、あるいはもっと頻繁に、週に数回、ホスティング プラットフォーム全体に小さな変更が加えられています。新機能やバグ修正を毎月の大規模なリリースにまとめるのではなく、本番環境への導入準備が整い次第、リリースします。
そして彼らは走らなければならないのです!
変更を本番環境に展開する場合、私たちは主に Puppet と Debian パッケージを使用して、顧客プロジェクトを実行しているアプリケーション サーバーとデータベース サーバー上のソフトウェアを更新します。そのほか、セキュリティ更新が利用可能になると、すべてのサーバーにそれをインストールするための無人アップグレードと呼ばれるプログラムもあります。
したがって、この Java プロセスが過度に拡大すると、これらのいずれも発生しなくなる可能性があります。リリースをインストールしないと、アプリケーションがデプロイメント システムの残りの部分と互換性の問題に陥る可能性があります。セキュリティ更新を見逃すことは、誰も望んでいないことです。
幸いなことに、この問題はごく限られた数の環境でのみ発生しています (現時点では、すべてのアプリケーション環境の 0.53%)。
Linux カーネルが救世主です!
ここで何が起こっているのかを調べ、この動作を修正するためのプロセスの最初のステップは、状況についてさらに詳しい情報を提供することです。
Java プロセスが 512MB のヒープ スペースを使用するように設定されている場合、これは一体何を意味するのでしょうか。上記の Java ヒープ グラフは、Java コード内で使用される実際のオブジェクトを格納するために使用されているメモリの一部を示しています。しかし、Java プロセスを実行するには、Java プログラム自体を起動する必要があります。このプログラムもメモリ内に存在する必要がありますか。この JVM ヒープ メモリ内に配置されているのでしょうか。プロジェクトの userlib の場所に配置した膨大な数の jar ファイルはどうでしょうか。それらに何が起こるのでしょうか。
これをよりよく理解するには、Java ヒープ領域だけでなく、オペレーティング システム内で Java プロセス全体が占めるメモリ領域を示すグラフがあると便利です。
…詳細なメモリ使用量情報を提供することで
幸いなことに、Linux カーネルでは、proc ファイル システムを使用して、単一のプロセスが占有しているメモリ アドレス空間の完全な概要を取得できます。前に示したサンプルの Java プロセスの PID (プログラム識別子) は 19137 です。つまり、Linux シェル プロンプトで次のコマンドを発行すると、Linux カーネルがこのプロセスのメモリ割り当てに関するすべての情報を表示できます。cat /proc/19137/smaps
利用可能な smaps 情報を使用すると、JVM プロセス内で何が起こっているかについて、かなり正確な推測を行うことができます。
このページに表示される最初のアプリケーション グラフに属する新しい JVM プロセス メモリ使用量グラフを紹介します。

なるほど! メモリを占有していたのは、結局 512MB の Java ヒープではありませんでした。約 230MB で、他の部分は Java オブジェクト ヒープの外部に割り当てられたメモリによって占有されているようです。その一部は永続的な生成とコード キャッシュで、JVM がガベージ コレクションの対象にはならないと判断したオブジェクトが格納されます。アプリケーションが実行中である限り、これらのオブジェクトは消えることはありません。別の部分はネイティブ メモリ部分です。
次に、問題のあるアプリケーションに属するグラフを見てみましょう。

このシナリオでは、Java ヒープはアクティブに使用されるため、実際に必要なときに使用可能になることが約束されているのではなく、実際にはオペレーティング システムによって割り当てられています。
ここでの主なポイントは、実際のオペレーティング システム メモリが JVM オブジェクト ヒープによって完全に占有されていると思い込んでいたが、実際はそうではなかったということです。
本当に手に負えなくなってきたら…
このブログ投稿の締めくくりとして、健全な行動の限界を本当に超えている状況の例を挙げます。
ここでは、1024 MB の Java オブジェクト ヒープから 512 GB のオブジェクト ヒープにアップグレードされた 1 MB の Java ヒープ構成を示します。

残念ながら、JVM プロセスのメモリ使用量が急増したため、それに対処するためにオペレーティング システムのサイズを変更する必要がありました。

新しい JVM プロセス メモリ グラフには、ここで何が起こっているかが表示されます。

継続するには...
過去数週間に行われた調査では、ヒープメモリ不足の問題の増加に対するいくつかの解決策がすでに示されています。今後のブログ投稿でそれらについて詳しく説明します。前述のリリースおよびセキュリティ更新の問題に遭遇している顧客アプリケーションは、 Mendix 短期的にこれらの問題にどのように対処するかについてです。
仕組み
これらのグラフを描くために、Linux procファイルシステムのsmapsファイルにあるすべての情報を調べました。いくつかのビットをリバースエンジニアリングし、推測することで、トレンドを作成するために使用するm2eeモニタリンググラフ構成の拡張機能を作成しました。Linuxカーネルからのsmaps情報を調べるモニタリングプラグインコードは、 m2ee-tools ソースコードを選択します。 munin プラグインのドキュメント 必要に応じてこのプラグインを自分で有効にする方法についてのヒントがいくつか含まれています。