Java がクロスプラットフォームを実現できる根本的な理由の 1 つは、クラス ファイルの形式標準を定義していることです。この標準を実装する JVM であれば、クラス ファイルをロードして解釈できます。これに基づいて、Java 言語の実行速度が C/C++ 言語よりも遅い理由もわかります。もちろん、これ以外にも理由はあります。例えば、JVM にはデータレジスタがなく、命令セットでは中間データを保存するのにスタックを使用します... Java の貢献者は、JIT、動的コンパイラなど、実行速度を向上させるためにさまざまな方法を考えていますが、以下は、異なる言語で実装された場合の Leetcode の問題の実行パフォーマンスの比較チャートです... 以下は JVM の基本的なアーキテクチャ図です。この基本的なアーキテクチャ図では、スタックは Java スレッド スタックとネイティブ メソッド スタックの 2 つの部分で構成されています。スタックの概念は基本的に C/C++ プログラムの概念と同じです。スタックフレームを格納します。スタック フレームは関数呼び出しを表します。関数の仮パラメータ、ローカル変数、戻りアドレスなどはスタック フレームに格納されます。ただし、C/C++ との重要な違いは、C/C++ では値渡しとアドレス渡しが区別されることです。オブジェクトが渡されると (構造体もオブジェクトと見なすことができます。実際、構造体もオブジェクトですが、その中のメソッドはデフォルトでパブリックです。信じられない場合は、構造体に関数を追加してみてください。コンパイラはエラーを報告せず、プログラムは引き続き実行されます~~~)、オブジェクトはスタックにコピーされます。 Java では、基本型のみが値によって渡され、他の型は参照によって渡されます。参照とは何ですか? C/C++を学んだ人なら、参照をポインターとして理解できますよ~~~。この基本的なアーキテクチャ図では、JVM がネイティブ メソッド スタックも定義していることがわかります。ネイティブ メソッド スタックは、Java がネイティブ メソッドを呼び出すために使用されます (これらのネイティブ メソッドは他の言語で記述されています)。 上の図に示すように、JVM には 2 つのスタックがありますが、ヒープは 1 つだけです。各スレッドには独自のスレッド スタックがあります [スレッド スタックのサイズは、JVM の -xss パラメータを設定することで構成できます。 32 ビット システムでは、各スレッド スタックのサイズは JDK5.0 以降は 1M になり、それ以前は各スレッド スタックのサイズは 256K でした。スレッド スタック内のデータはスレッド専用ですが、すべてのスレッドがヒープ領域を共有します。オブジェクト データはヒープ内に格納されます。オブジェクトデータとは何ですか?消去法に従って、基本型と参照型以外のデータはヒープ領域に配置されます。メソッド領域とヒープは、すべてのスレッドで共有されるデータ領域です。 1. プログラムカウンタ CPU レジスタには PC レジスタがあり、次の命令のアドレスが格納されます。ここで、仮想マシンは CPU プログラム カウンターを使用せず、CPU プログラム カウンターをシミュレートするための領域をメモリ内に設定しています。プログラム カウンターが 1 つだけでは不十分です。複数のスレッドが実行を切り替える場合、単一のプログラム カウンターでは不十分になります。仮想マシンの仕様では、各スレッドには独立したプログラム カウンターがあることが規定されています。 Java 仮想マシンのプログラム カウンタは、次のバイトコードのアドレスではなく、実行中のバイトコードのアドレスを指していることに注意してください。 2. Java仮想マシンスタック Java 仮想マシン スタックもスレッドプライベートです。仮想マシン スタックは、Java メソッド実行のメモリ モデルを記述します。各メソッドが実行されると、ローカル変数テーブル、オペランド スタック、動的リンク、メソッド終了などの情報を格納するスタック フレームが作成されます。各メソッドの呼び出しから実行完了までの処理は、仮想マシン内でスタック フレームがプッシュされてポップされる処理に対応します。通常、メモリはヒープ メモリとスタック メモリに分けられます。スタック メモリは、仮想マシン スタックのローカル変数テーブル部分を指します。ローカル変数テーブルには、コンパイル時に認識される基本データ型 (boolean、byte、char、short、int、float、long、double)、オブジェクト参照 (オブジェクトの開始アドレスを指す参照ポインター、またはオブジェクトまたはオブジェクトに関連するその他の場所を表すハンドル)、および戻った後に指されるバイトコードのアドレスが格納されます。このうち、64 ビットの long および double データ型は 2 つのローカル変数空間 (スロット) を占有し、残りのデータ型は 1 つのみを占有します。ローカル変数テーブルに必要なメモリ空間は、コンパイル時に割り当てられます。メソッドに入ると、このメソッドがフレーム内に割り当てる必要があるローカル変数スペースの量が完全に決定され、メソッドの実行中にローカル変数テーブルのサイズは変更されません。再帰レベルが深すぎると、仮想マシン スタックによってスローされる例外である java.lang.StackOverflowError がトリガーされます。 3. ネイティブメソッドスタック HotSpot 仮想マシンは、ローカル メソッド スタックと仮想マシン スタックを 1 つに結合します。それらの違いは、仮想マシン スタックは Java メソッドの実行を提供するのに対し、ローカル メソッド スタックは仮想マシンで使用されるネイティブ メソッドを提供するという点です。 4. Javaヒープ Java ヒープはすべてのスレッドで共有されるメモリ領域であり、仮想マシンの起動時に作成されます。この領域はオブジェクト インスタンスを格納するために使用され、ほとんどすべてのオブジェクト インスタンスがここにメモリを割り当てます。ヒープは、オブジェクトの自動破棄を実装する Java ガベージ コレクター (GC ヒープ) によって管理される主要な領域です。 Java ヒープは、新しい世代と古い世代に分割できます。より詳細なものとしては、Eden 空間、From Survivor 空間、To Survivor 空間などがあります。Java ヒープは、ディスク空間と同様に、論理的に連続している限り、物理的に不連続なメモリ空間に存在できます。 -Xmx および -Xms で制御できます。 5. 方法領域 メソッド領域は第 1 世代とも呼ばれます。過去 (カスタム クラス ローダーがあまり一般的ではなかった頃) は、クラスはほとんどが「静的」であり、アンロードまたは収集されることはほとんどなかったため、「永続的」と呼ばれていました。 Java 仮想マシン仕様では、メソッド領域はヒープ論理部分として説明されていますが、メソッド領域には Non-Heap という別名があり、その目的は Java ヒープと区別することです。同時に、クラスは JVM 実装の一部であり、アプリケーションによって作成されるものではないため、「非ヒープ」メモリともみなされます。 HotSpot 仮想マシンの設計チームは、GC 世代別コレクションをメソッド領域に拡張するか、最初の世代を使用してメソッド領域を実装するかを選択しました。その他の仮想マシン (BEA JRockit、IBM J9 など) には、第 1 世代の概念はありません。 第 1 世代もすべてのスレッドで共有される領域です。仮想マシンによってロードされたクラス情報、定数、静的変数 (JDK7 では Java ヒープへ移動)、ジャストインタイムコンパイル期間中にコンパイルされたコード (クラスメソッド)、およびその他のデータを格納するために使用されます。ここで、メソッド領域の一部であり、コンパイル時に生成されるさまざまなリテラルとシンボリック参照 (実際には、8 つの基本型のパッケージ型と文字列型データ (JDK7 で Java ヒープへ移動)) を格納するために使用されるランタイム定数プールについて説明する必要があります (公式ドキュメントの説明: JDK 7 では、インターン化された文字列は Java ヒープの永続世代に割り当てられなくなり、代わりにアプリケーションによって作成された他のオブジェクトとともに、Java ヒープのメイン部分 (若い世代と古い世代と呼ばれる) に割り当てられます)。 JDK1.7 の HotASpot では、メソッド領域に元々配置されていた文字列定数プールが移動されました。
JDK7 からは、第 1 世代の削除が開始され、第 1 世代に格納されていたデータの一部が Java ヒープまたはネイティブ ヒープに転送されるようになりました。しかし、最初の世代は JDK7 にまだ存在しており、完全に削除されていません。シンボル参照 (シンボル) はネイティブ ヒープへ移動されます。リテラル(インターン化された文字列)は Java ヒープに移動されます。クラスの静的変数 (クラス静的) は Java ヒープへ移動されます。 JDK8 の登場により、JVM には PermGen がなくなりました。ただし、クラス メタデータ情報はまだ存在しますが、連続したヒープ スペースに保存されるのではなく、「Metaspace」と呼ばれるネイティブ メモリに移動されます。 JVM 内の共有データ領域は以下のように分割されます。 上の図は、Java プログラムの実行中のヒープ領域を示しており、簡単に説明すると次のようになります。 1. JVM の共有データ領域は、Young Generation、Old Generation、Permanent Generation の 3 つの主要領域に分けられます。 JVM ヒープは、Young 世代と Old 世代に分かれています。 2. 新しい世代は、Eden 領域 (新しいオブジェクトを格納するため) と 2 つの Survivor 領域 (From Survivor と To Survivor) (各ガベージ コレクションを生き残ったオブジェクトを格納するため) の 3 つの領域に分けられます。 3. 最初の世代は、クラス ファイル、静的オブジェクト、属性などを管理します (JVM は、Java クラスの内部表現を保持するために、Permanent Generation (略して PermGen) と呼ばれる別のメモリ領域を使用します。PermGen は、さらに多くの情報を格納するためにも使用されます)。 4. JVM ガベージ コレクション メカニズムは「世代別コレクション」を採用しています。新しい世代はコピー アルゴリズムを採用し、古い世代はマーク スイープ アルゴリズムを採用しています。 オペレーティング システム プロセスとして、Java ランタイムは、オペレーティング システム アーキテクチャによって提供されるアドレス指定可能なアドレス空間とユーザー空間という、他のプロセスとまったく同じメモリ制限に直面します。 オペレーティング システム アーキテクチャによって提供されるアドレス指定可能なアドレス空間は、プロセッサのビット数によって決まります。 32 ビットでは、2^32、つまり 4,294,967,296 ビット、つまり 4 GB のアドレス指定可能な範囲が提供されます。 64 ビット プロセッサのアドレス指定可能な範囲は大幅に広く、2^64、つまり 18,446,744,073,709,551,616、つまり 16 エクサバイトになります。 アドレス空間はユーザー空間とカーネル空間に分かれています。カーネルは、メインのオペレーティング システム プログラムと C ランタイムであり、コンピューターのハードウェアやスケジューラに接続し、ネットワークや仮想メモリなどのサービスを提供するために使用されるロジックと C ベースのプロセス (JVM) が含まれています。カーネル空間を除いたものがユーザー空間であり、これは Java プロセスの実行時に実際に使用されるメモリです。 デフォルトでは、32 ビット Windows には 2 GB のユーザー スペースと 2 GB のカーネル スペースがあります。一部のバージョンの Windows では、ブート構成に /3GB スイッチを追加し、/LARGEADDRESSAWARE スイッチを使用してアプリケーションを再リンクすることで、このバランスを 3GB のユーザー スペースと 1GB のカーネル スペースに調整できます。 32 ビット Linux では、デフォルト設定は 3 GB のユーザー スペースと 1 GB のカーネル スペースです。一部の Linux ディストリビューションでは、4GB のユーザー スペースをサポートする hugemem カーネルが提供されています。この構成を実現するために、システム コールを行うときに使用するアドレス空間がカーネルに割り当てられます。このようにユーザー空間を追加すると、システムコールが行われるたびに OS がアドレス空間間でデータをコピーし、プロセスのアドレス空間マッピングをリセットする必要があるため、システムコールの速度が低下します。 次の図は、32 ビット Java プロセスのメモリ レイアウトを示しています。 アドレス可能なアドレス空間の合計は 4GB で、そのうち OS と C ランタイムが約 1GB、Java ヒープが約 2GB、ネイティブ ヒープが残りを占めます。 OS カーネルや C ランタイムと同様に、JVM 自体もメモリを占有することに注意してください。 知らせ: 1. 上記のアドレス可能空間は*** アドレス空間を指します。 2. ユーザー空間が 2GB の場合、理論上は Java ヒープメモリの最大値は 1.75G ですが、Java スレッドヒープが 1.75G に達すると、ローカルヒープでメモリ不足エラーが発生するため、実際に Java ヒープで使用可能なメモリの最大値は 1.5G です。 JVM の実行中に、次のパラメータを構成することで、JVM ヒープ全体の構成比率を変更できます。
上記の構成では、古い世代が占有する領域のサイズは、パラメータ -XX:SurvivorRatio によって構成されます。上記の JVM ヒープ スペース割り当て図を読んだ後、新しい世代のスペースが 3 つの領域、Eden、および 2 つの Survivor 領域に分割されている理由が疑問に思うかもしれません。目的は何ですか?なぜこのように分かれているのでしょうか?この問題を理解するには、JVM のガベージ コレクション メカニズム (コピー アルゴリズムはコピー アルゴリズムとも呼ばれます) を理解する必要があります。手順は次のとおりです。 コピーアルゴリズム メモリを A と B の 2 つのブロックに均等に分割します。アルゴリズムのプロセスは次のとおりです。 1. 新しいオブジェクトがブロック A の未使用メモリに割り当てられます。ブロック A のメモリが使い果たされると、ブロック A の残りのオブジェクトがブロック B にコピーされます。 2. ブロック A 内のすべてのオブジェクトをクリーンアップします。 3. 新しく作成されたオブジェクトは、ブロック B の未使用のメモリに割り当てられます。ブロック B のメモリが使い果たされると、ブロック B の残りのオブジェクトがブロック A にコピーされます。 4. ブロック B 内のすべてのオブジェクトをクリーンアップします。 5. 1に戻ります。 利点: シンプルで効率的。デメリット: メモリコストが高く、実効メモリは占有メモリの半分です。 図は次のようになります。(図の背面図は循環プロセスです) レプリケーションアルゴリズムのさらなる最適化:3つのパーティションEden/S0/S1の使用 A/B ブロックに均等に分割すると、メモリが無駄に消費されすぎます。 Eden/S0/S1 の 3 つの領域を使用する方が合理的です。スペース比率はEden:S0:S1==8:1:1で、実効メモリ(新規オブジェクトに割り当て可能なメモリ)は総メモリの9/10となります。 アルゴリズムプロセス: 1. Eden+S0 は新しいオブジェクトを割り当てることができます。 2. Eden+S0 でガベージ コレクションを実行し、生き残ったオブジェクトを S1 にコピーします。 Eden+S0をクリーンアップします。新世代GCが終了します。 3. Eden+S1は新しいオブジェクトを割り当てることができます。 4. Eden+S1 でガベージ コレクションを実行し、生き残ったオブジェクトを S0 にコピーします。 Eden+S1をクリーンアップします。第2世代の新GCが終了。 5. 1に戻ります。 デフォルトでは、Eden:S0:S1=8:1:1 です。したがって、新世代で使用可能なメモリ領域は、新世代の 9/10 を占めます。すると、なぜ直接 2 つのエリアに分割されないのか、1 つのエリアが 9/10 を占め、もう 1 つのエリアが 1/10 を占めるのかと疑問に思う人もいるでしょう。これにはおそらく次のような理由があります。 1. S0とS1の間隔が大幅に小さくなり、有効な新世代空間はEden+S0/S1になるため、有効な空間が大きくなり、メモリ使用率が高くなります。 2. オブジェクト生成の計算に役立ちます。オブジェクトが S0/S1 で設定された XX:MaxTenuringThreshold 値に達すると、古い世代に分割されます。 S0/S1 が存在せず、直接 2 つの領域に分割されている場合、オブジェクトが GC を通過して解放されなかった回数をどのように計算するのでしょうか?通過した GC の数を記録するためのカウンターがオブジェクトに追加されている、またはオブジェクトと GC の数の関係を記録するためのマッピング テーブルがあると言えます。はい、可能ですが、その場合、新しい世代全体のオブジェクトがスキャンされます。 S0/S1ではS0/S1領域のみをスキャンできます~~~ 参考: http://my.oschina.net/hosee/blog/638753 |
>>: DevOps の今後の発展に影響を与える 5 つのトレンド!
多くの企業にとって、クラウド リソースの活用は戦略の一部ではなく、個々のチームがニーズを満たすために...
柔軟性からフェイルオーバー保護まで、企業がマルチクラウド戦略を選択する理由は数多くあります。 IDC...
2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っていますSEO 業...
私がインターネットに触れ始めたのは、2011 年後半のことでした。最初の宝は心を打つコメントから、そ...
2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています多くの企業...
2020-12-23 09:35 市場調査会社IDCが発表した最新のレポートによると、2020年上半...
オンライン マーケティングが Web サイトのキーワード ランキングに与える影響はますます大きくなり...
最初にウェブサイトを構築したとき、SEOについて何も知りませんでした。トラフィックを獲得するために、...
v.ps は、イースターシーズン中にヨーロッパの VPS サイクルの 50% 割引プロモーションを開...
アリババクラウドは7月31日、南通、杭州、ウランチャブにある3つのスーパーデータセンターが正式に完成...
Amazon Web Services は、2022 re:Invent Global Confer...
1997 年に設立された完全管理型サーバー ホスティング プロバイダーの Liquidweb も、今...
なぜ中小企業では SEO 計画やプログラムが失敗するのでしょうか? SEO 担当者が策定した計画やプ...
検索エンジンは、今日でもインターネット上の重要なマーケティング ツールです。有能な Web サイト管...
みなさんこんにちは。SEO に関する記事を書いてからしばらく経ちました。主な理由は、Baidu が最...