Linux仮想メモリについての簡単な説明

Linux仮想メモリについての簡単な説明

起源

仮想メモリ

仮想メモリは、間違いなくオペレーティング システムで最も重要な概念の 1 つです。それは主に、記憶の「戦略的位置」の重要性によるものだと思います。 CPU は高速ですが、容量が小さく、機能が制限されています。他の I/O ハードウェアはさまざまな高度な機能をサポートしていますが、CPU と比較すると遅すぎます。したがって、それらの間には緩衝材として機能する潤滑剤が必要であり、ここでメモリが役立ちます。

上の図は、仮想メモリの最もシンプルで直感的な説明です。

オペレーティング システムには、物理​​メモリの一部 (中央部分) と 2 つのプロセス (実際にはさらにあります) P1 と P2 があります。オペレーティング システムは、P1 と P2 にそれぞれ秘密裏に、メモリ全体があなたのものであり、好きなように好きなだけ使用できることを伝えます。しかし実際には、オペレーティング システムは、すべてのメモリが P1 と P2 に割り当てられていると大まかなイメージを描き出しただけで、実際にはシリアル番号しか割り当てていませんでした。 P1 と P2 が実際にメモリを使い始めると、システムはプロセスが使用するブロックを移動して組み立て始めます。P2 はメモリ A を使用していると考えていますが、実際にはシステムによって実メモリ B に静かにリダイレクトされています。P1 と P2 がメモリ C を共有している場合でも、P1 と P2 はそれを認識していません。

オペレーティング システムがプロセスを欺く方法は仮想メモリです。 P1 や P2 などのプロセスは、すべてメモリ全体を占有していると考えていますが、物理メモリのどのアドレスを使用しているかは知らず、気にする必要もありません。

ページングとページテーブル

仮想メモリは、オペレーティング システムの概念です。オペレーティング システムにとって、仮想メモリは一連の比較テーブルです。P1 がメモリ A でデータを取得する場合は、物理メモリのアドレス A に移動し、メモリ B でデータを検索する場合は、物理メモリのアドレス C に移動する必要があります。

システムの基本単位はバイトであることはご存じのとおりです。仮想メモリの各バイトが物理メモリのアドレスにマッピングされる場合、各エントリには少なくとも 8 バイトが必要です (32 ビット仮想アドレス -> 32 ビット物理アドレス)。4G メモリの場合、比較テーブルを格納するには 32GB のスペースが必要です。このテーブルは大きすぎて、実際の物理アドレスを収容できません。そのため、オペレーティング システムではページの概念が導入されています。

システムが起動すると、オペレーティング システムは物理メモリ全体を 4K 単位のページに分割します。その後メモリを割り当てる際、ページを単位として使用されます。そのため、物理メモリ ページに対応する仮想メモリ ページのマッピング テーブルが大幅に削減されます。4G メモリの場合、必要なマッピング テーブルは 8M のみです。一部のプロセスで使用されていない仮想メモリのマッピング関係を保存する必要がありません。さらに、Linux は大容量メモリ用にマルチレベル ページ テーブルを設計しており、これによりメモリ消費をさらに削減できます。オペレーティング システムの仮想メモリから物理メモリへのマッピング テーブルは、ページ テーブルと呼ばれます。

メモリのアドレス指定と割り当て

仮想メモリのメカニズムにより、各プロセスはメモリをすべて占有していると考えることがわかっています。プロセスがメモリにアクセスすると、オペレーティング システムはプロセスによって提供された仮想メモリ アドレスを物理アドレスに変換し、対応する物理アドレスからデータを取得します。 CPU には一種のハードウェアがあり、メモリ管理ユニット MMU (Memory Management Unit) は特に仮想メモリ アドレスの変換に使用されます。 CPU はページ テーブル アドレス指定のキャッシュ戦略も設定します。プログラムの局所性により、キャッシュ ヒット率は 98% に達します。

上記の状況は、ページ テーブルに仮想アドレスから物理アドレスへのマッピングがあるということです。プロセスがアクセスした物理アドレスが割り当てられていない場合、システムはページ フォールト割り込みを生成します。割り込みが処理されると、システムはカーネル状態に切り替わり、プロセスの仮想アドレスに物理アドレスを割り当てます。

関数

仮想メモリは、メモリ アドレス変換を通じて複数のプロセス間のメモリ アクセス競合の問題を解決するだけでなく、さらに多くの利点をもたらします。

プロセスメモリ管理

主に以下の点でプロセスがメモリを管理するのに役立ちます。

  • メモリの整合性: プロセスに対する仮想メモリの「欺瞞」により、各プロセスは取得したメモリが連続したアドレスであると信じます。アプリケーションを作成するときに、大きなアドレス ブロックの割り当てを考慮する必要はありません。システムには常に十分な大きさのメモリ ブロックがあると想定できます。
  • セキュリティ: プロセスがメモリにアクセスするたびに、ページ テーブルを介してメモリをアドレス指定する必要があるため、オペレーティング システムは、ページ テーブルの各項目にさまざまなアクセス許可識別ビットを追加することで、メモリアクセス許可制御を実装できます。

データ共有

仮想メモリを使用すると、メモリとデータを共有しやすくなります。

プロセスがシステム ライブラリをロードする場合、必ず最初にメモリ ブロックを割り当て、ライブラリ ファイルをディスクからこのメモリにロードします。物理メモリを直接使用する場合、物理メモリ アドレスは一意であるため、システムで同じライブラリが 2 回ロードされていることが検出されたとしても、各プロセスによって指定されたロード メモリが異なり、システムは何もできません。

仮想メモリを使用する場合、システムは、プロセスの仮想メモリ アドレスを、ライブラリ ファイルが配置されている物理メモリ アドレスにポイントするだけで済みます。上の図に示すように、プロセス P1 と P2 の B アドレスは両方とも物理アドレス C を指しています。

仮想メモリを使用すると、共有メモリを使用するのも非常に簡単です。システムは、各プロセスの仮想メモリ アドレスを、システムによって割り当てられた共有メモリ アドレスにポイントするだけで済みます。

スワップ

仮想メモリにより、プロセスはメモリを「拡張」できるようになります。

先ほど、仮想メモリはページ フォールト割り込みを通じてプロセスに物理メモリを割り当てると述べました。メモリは常に制限されています。すべての物理メモリが占​​有されたらどうなるでしょうか?

Linux は SWAP の概念を提案しています。Linux では SWAP パーティションを使用できます。物理メモリが割り当てられているが、使用可能なメモリが不足している場合、一時的に使用されていないメモリ データが最初にディスクに配置され、必要なプロセスが最初に使用できるようになります。プロセスがこのデータを再度使用する必要がある場合、データはメモリにロードされます。この「スワップ」テクノロジにより、Linux はプロセスがより多くのメモリを使用できるようにします。

よくある質問

仮想メモリについて学ぶときにも、多くの疑問がありました。

32 ビットと 64 ビット

最も一般的な問題は、32 ビットと 64 ビットです。

CPU は物理バスを介してメモリにアクセスするため、アクセス アドレスの範囲はマシン バスの数によって制限されます。32 ビット マシンには 32 のバスがあり、各バスにはそれぞれビット 1 と 0 を表す高電位と低電位があります。アクセス可能な最大アドレスは 2^32bit = 4GB です。したがって、32 ビット マシンに 4G を超えるメモリを挿入することは無効であり、CPU は 4G を超えるメモリにアクセスできません。

ただし、64 ビット マシンには 64 ビット バスがなく、最大メモリはオペレーティング システムによって制限されます。Linux は現在、最大 256G のメモリをサポートしています。

仮想メモリの概念によれば、32 ビット システムで 64 ビット ソフトウェアを実行することは不可能ではありません。ただし、システムの仮想メモリ アドレスの構造設計により、64 ビットの仮想アドレスは 32 ビット システムでは使用できません。

物理メモリを直接操作する

オペレーティングシステムは仮想メモリを使用します。メモリを直接操作したい場合はどうすればよいでしょうか?

Linux は各デバイスを /dev/ ディレクトリ内のファイルにマッピングします。これらのデバイス ファイルを通じてハードウェアを直接操作することができ、メモリも例外ではありません。 Linux ではメモリ設定は /dev/mem にマッピングされており、root ユーザーはこのファイルを読み書きすることでメモリを直接操作できます。

JVMプロセスが仮想メモリを占有しすぎている

TOP を使用してシステム パフォーマンスを表示すると、VIRT 列で Java プロセスが大量の仮想メモリを占有していることがわかります。

この問題の原因は、Java が Glibc の Arena メモリ プールを使用して大量の仮想メモリを割り当て、それを使用しないことです。さらに、Java によって読み取られるファイルも仮想メモリとしてマップされます。仮想マシンのデフォルト構成では、各 Java スレッド スタックは 1M の仮想メモリを占有します。 Linux でマルチスレッド プログラムが大量の仮想メモリを消費する理由を確認できます。

実際に占有されている物理メモリは、RES (resident) 列で確認できます。この列の値は、実際に物理メモリにマップされているサイズです。

一般的な管理コマンド

Linux の仮想メモリを自分で管理することもできます。

システムメモリの状態を確認する

システム メモリの状態を確認する方法は多数あります。free や vmstat などのコマンドを使用すると、現在のシステム メモリの状態を出力できます。使用可能なメモリは、free 列だけではないことに注意してください。オペレーティング システムの遅延特性により、プロセスが使用されなくなった後も、多数のバッファ/キャッシュはすぐにクリーンアップされません。以前にそれらを使用していたプロセスが再び実行されると、それらは引き続き使用され、必要に応じて使用できます。

さらに、cat /proc/meminfo を使用すると、ダーティ ページの状態など、システム メモリの使用状況に関する詳細情報を表示できます。詳細については、/PROC/MEMINFO の謎を参照してください。

ピマップ

特定のプロセスの仮想メモリの分布を個別に表示する場合は、pmap pid コマンドを使用できます。このコマンドは、各仮想メモリ セグメントの占有率を低アドレスから高アドレスまで一覧表示します。

-XX パラメータを追加すると、より詳細な情報を出力できます。

メモリ構成を変更する

Linux システム構成を変更することもできます。sysctl vm [-options] CONFIG を使用するか、/proc/sys/vm/ ディレクトリ内のファイルを直接読み書きして、構成を表示および変更します。

SWAP操作

仮想メモリの SWAP 機能は必ずしも有益ではありません。プロセスがメモリとディスク間で大量のデータを絶えず交換できるようにすると、CPU が大幅に占有され、システム効率が低下するため、スワップを使用したくない場合があります。

vm.swappiness=0 を変更して、メモリがスワップをできるだけ使用しないように設定するか、swapoff コマンドを使用して SWAP を無効にすることができます。

まとめ

仮想メモリの概念は非常に理解しやすいですが、非常に複雑な一連の知識につながります。この記事では、いくつかの基本原則についてのみ説明し、仮想メモリのアドレス指定におけるセグメント レジスタの使用、キャッシュおよびバッファ アプリケーションを強化するためのオペレーティング システムでの仮想メモリの使用など、多くの詳細については省略します。これらについては、機会があれば別途説明します。

上記は Linux 仮想メモリの詳細についての簡単な説明です。Linux 仮想メモリの詳細については、123WORDPRESS.COM の他の関連記事をご覧ください。

以下もご興味があるかもしれません:
  • Linux仮想マシンを作成し、仮想マシンネットワークを設定する方法に関するVMwareの詳細なチュートリアル
  • 仮想マシン VMware に Kali Linux をインストールする最新の超詳細なグラフィック チュートリアル
  • オペレーティングシステムにおける仮想アドレスと物理アドレスの簡単な分析

<<:  Vue 開発プロジェクトで Font Awesome 5 を使用する方法

>>:  ウェブページ作成のテスト問題を全て解けますか?

推薦する

MySQL 5.7.17 winx64 のインストールと設定のグラフィックチュートリアル

MySQL のインストールに関する以前のメモを要約して、皆さんと共有しました。ステップ 1: mys...

HTMLでマスクレイヤーを実装する方法 HTMLでマスクレイヤーを使用する方法

Web ページでマスク レイヤーを使用すると、繰り返しの操作を防ぎ、読み込みを促進できます。また、ポ...

CSS で垂直方向の中央揃えを行う 7 つの方法の詳細なコード例

レイアウトを編集するとき、通常は水平センタリングと垂直センタリングを使用してデザインします。水平セン...

クロスオリジン画像リソース権限(CORS 対応画像)

HTML 仕様書では、画像の crossorigin 属性が導入されています。適切なヘッダー情報 ...

MySQL で GTID モードをオンラインで有効または無効にする

目次基本的な概要GTIDをオンラインで有効にする1. GTID検証ENFORCE_GTID_CONS...

JavaScriptを使用して独自のAjax関数を定義する

ネイティブJSによって開始されたネットワークリクエストは、クエリ文字列の形でサーバーに送信されるため...

MySQL 8.0.17 をインストールしてリモート アクセスを構成する方法

1. インストール前の準備データベースのバージョンを確認するコマンド: mysql --versio...

MySQLデータベースの数千万件のデータクエリとストレージの詳細な説明

目次百万レベルのデータ処理ソリューションデータストレージ構造設計クエリステートメントの最適化1000...

antd pro に基づく SMS 認証コード ログイン機能 (プロセス分析)

目次まとめ全体的なプロセスフロントエンドページコード検証コードとログイン サービスをリクエストする ...

LeetCode の SQL 実装 (175. 2 つのテーブルの結合)

[LeetCode] 175.2つのテーブルを結合する表: 人物+-------------+--...

Nginxにモジュールを動的に追加する方法

前面に書かれた多くの場合、現在のプロジェクトの状況とビジネスニーズに基づいて Nginx をインスト...

アルバムと写真をアルバムに保存するためのWeChatアプレット

私は現在、Xiao Nian Gao に似たビデオおよびツール アプリを開発しています。ユーザーが作...

HTML の空リンク href="#" と href="javascript:void(0)" の違い

# には位置情報が含まれます。デフォルトのアンカーは #top で、これは Web ページの上部です...

SASSで変数のデフォルト値を使用する方法

SASS で定義された変数では、後で設定された値によって古い値が上書きされます。 $色: 赤; $色...

Ant Design Blazor コンポーネントライブラリのルーティング再利用マルチタブ機能

最近、Ant Design Blazor コンポーネント ライブラリにマルチタブ コンポーネントを実...