Linux のメモリ管理とアドレス指定の詳細な紹介

Linux のメモリ管理とアドレス指定の詳細な紹介

1. コンセプト

メモリ管理モード

セグメント型: メモリは複数のセグメントに分割され、各セグメントは連続したメモリであり、異なるセグメントは異なる用途に対応します。各セグメントのサイズが均一ではないため、メモリの断片化やメモリスワップの非効率などの問題が発生します。

ページ化: メモリは管理のために複数のメモリ ページに分割されます。たとえば、Linux システムでは、各ページのサイズは4KBです。ページングにより、小さなメモリ断片は発生しません。しかし、メモリの断片化の問題は依然として残っています。

段落ページ形式: 段落形式とページ形式の組み合わせ。

住所種別分類

論理アドレス: プログラムが使用するアドレス、通常はセグメントメモリ管理によってマップされていないアドレスを論理アドレスと呼びます。

リニアアドレス: セグメント化されたメモリ管理によってマップされるアドレスは、リニアアドレス、または仮想アドレスと呼ばれます。

仮想アドレス: セグメント化されたメモリ管理によってマップされたアドレスは、線形アドレス、または仮想アドレスと呼ばれます。

物理アドレス: 物理メモリアドレス

例:

Inetel プロセッサでは、論理アドレスは「セグメント メモリ管理」変換前のアドレスであり、リニア アドレスは「ページ メモリ管理」変換前のアドレスです。

セグメント化されたメモリ管理によってマップされるアドレスはもはや「物理アドレス」ではなく、Intel では「リニア アドレス」(仮想アドレスとも呼ばれる) と呼ばれています。したがって、セグメント化メモリ管理では、まず論理アドレスをリニア アドレスにマッピングし、次にページ化メモリ管理ではリニア アドレスを物理アドレスにマッピングします。

Linux のメモリは主にページ メモリによって管理されますが、セグメント メカニズムも使用されます。 Linux カーネルが現在採用しているアプローチは、セグメント マッピング プロセスを事実上無効にすることです。

Intel の最も初期のプロセッサである 80286 は完全にセグメントベースでしたが、80386 にはセグメントとページの両方の管理機能がありました。

2. ページ管理

x86 アーキテクチャ 32 ビット CPU

セカンダリ ページ テーブル アドレス指定方法では、メモリ ページのサイズは 4 KB、第 1 レベルのページ ディレクトリ テーブルには 1024 個のエントリがあり、第 2 レベルのページ テーブルには 1024 個のエントリがあり、ページ テーブル エントリは 4 バイトです。第 1 レベルのページ ディレクトリ テーブル エントリがすべて割り当てられ、必要に応じて第 2 レベルのページ テーブルが作成されます。 (局所性原理)。

仮想アドレス 32 ビット

10+10+12 は、それぞれレベル 1 ページ テーブル番号、レベル 2 ページ テーブル エントリをインデックスし、物理ベース アドレスのオフセット アドレスを記録します。 PAE メカニズムを使用した後、32 ビット システムでサポートされる最大メモリは 64 GB (アドレスは 32+4=36 ビット) になります。

線形アドレス指定物理アドレスステップ

まず、10 ビットのアドレス指定レベル 1 ページ テーブル番号を使用します。レベル 1 ページ テーブル番号には、レベル 2 ページ テーブルのアドレスが記録されます。

レベル 2 ページ テーブルのアドレスを見つけた後、仮想アドレスの残りの 10 ビットに基づいて、レベル 2 ページ テーブル内のエントリの場所が見つかります。

レベル 2 ページ テーブルのエントリが見つかると、エントリには物理アドレスにマッピングされる仮想アドレスの開始アドレスが記録されます。エントリのサイズは 4 バイト (32 ビット) です。

最終的な物理アドレスは、見つかった物理アドレスの開始アドレスと、仮想アドレスの最後の12ビットをオフセットとして組み合わせて計算されます。

x86 アーキテクチャ 64 ビット CPU

ページテーブルにはさらにレベルがある

グローバル ページ ディレクトリ PGD (ページ グローバル ディレクトリ) 上位ページ ディレクトリ PUD (ページ上位ディレクトリ) 中間ページ ディレクトリ PMD (ページ中間ディレクトリ) ページ テーブル エントリ PTE (ページ テーブル エントリ)

線形アドレス指定物理アドレスステップ

リニアアドレスは48ビット、最大物理アドレスは52ビット、実際の物理メモリアドレスバス幅は40ビットで、1TBの物理メモリをサポートします。x86_64には4レベルのページテーブルがあり、原理はx86システムと同じで、レイヤーごとにアドレス指定されます。CR3レジスタには最上位テーブルの開始物理アドレスが格納されているため、アドレス指定の最初のステップはCR3レジスタの値を取得することです。各PTEエントリのサイズは8バイト、つまり64ビットです。

TLB

CPU チップには、プログラムによって最も頻繁にアクセスされるページ テーブル エントリを格納するためのキャッシュが追加されています。このキャッシュは TL (Translation Lookaside Buffer) です。通常、ページ テーブル キャッシュ、リダイレクト バイパス キャッシュ、高速テーブルなどと呼ばれます。次に、CPU のメモリ管理ユニット MMU がアドレスを検索すると、最初に TLB をチェックします。見つからない場合は、通常のページ テーブルのチェックを続けます。

固有名詞

PDT: ページ ディレクトリ テーブル、マルチレベル ページ テーブル、第 1 レベル ページ テーブル、32 ビット システムには 1024 個のページ ディレクトリがあります
PTT: ページ テーブル エントリ、マルチレベル ページ テーブル、セカンダリ ページ テーブル、32 ビット システムでは各ページ ディレクトリの下に 1024 のページ テーブル エントリがあり、各エントリは 4 バイトです。
PDE: ページテーブルのベースアドレス。PDT内の項目です。
PTE: ページのベースアドレス、PTTの1つ
GDT: グローバル記述子テーブル。論理アドレスを線形アドレスに変換するために使用されます。
LDT: ローカル記述子テーブル。論理アドレスを線形アドレスに変換するために使用されます。

3. 住所区分

32 システムカーネル 1G: 0xC0 00 00 01 - 0xFF FF FF FF
ユーザー 3G: 0x00 00 00 00 - 0xC0 00 00 00
0xC0 00 00 00 == 3G

64 ビット システム:
カーネル 128T: 0xFF FF 80 00 00 00 00 00 - 0xFF FF FF FF FF FF FF FF (高)
0xFF FF 7F FF FF FF FF FF - 0xFF FF FF FF FF FF FF FF (自分で計算してください)

ユーザー 128T: 0x00 00 00 00 00 00 00 00 - 0x00 00 7F FF FF FF FF FF (下位)
0x00 00 80 00 00 00 00 00 00 - 0x00 00 80 00 00 00 00 00 (自分で計算してください)

0x00 00 7F FF FF FF FF FF == 127T
質問: 64 ビット システムの境界線は 128T ですか? 127T ですか?

アクセス権

プロセスがユーザー モードにある場合、ユーザー空間メモリにのみアクセスできます。カーネル モードに入った後にのみ、カーネル空間メモリにアクセスできます。

PAE メカニズム

CPU ビット幅とは、CPU が 1 クロック サイクル内で処理できるバイナリ ビットの数を指します。通常のシナリオでは、32 ビット システム CPU のアドレス バスは 32 ビットです。ただし、PAE メカニズムの導入後は、16 ビット CPU のアドレス バス ビット幅は 20 ビット (物理メモリ 1M)、32 ビット CPU のアドレス バスは 36 ビット (物理メモリ 64GB)、64 ビット CPU のアドレス バス ビット幅は 40 ビット (物理メモリ 1TB) になります。したがって、32 ビット システムは最大 4 GB のメモリ スティックのみをサポートすると単純に言うことはできません。

4. デバッグ

プログラム登録

cs: コードセグメントレジスタ
ds: データセグメントレジスタ
ss: スタックセグメントレジスタ
es: 拡張セグメントレジスタ
fs: 32ビット後のフラグセグメントレジスタ
gs: 32ビット後のグローバルセグメントレジスタ

カーネルクラッシュログの例:

RIP: 0010:[ ] [ ] xxxxxxxxxx+0x69/0x70
RSP: 0018:ffff886241737d98 EFLAGS: 00010246
RAX: ffff880034814d40 RBX: ffff881fc6248740 RCX: 00000000000000200
RDX: 0000000000000000 RSI: 0000000000000286 RDI: ffff881fc6381858
RBP: ffff886241737d98 R08: ffff886241734000 R09: 0000000000000000
R10: ffff880034814d40 R11: 00000000000000200 R12: ffff881fc62487a0
R13: 00000000000000000 R14: 00007fff86cb6260 R15: ffff881fc6381858
FS: 00007f78b59b8720(0000) GS:ffff885ffe3c0000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f690a057180 CR3: 0000006208985000 CR4: 00000000003627e0
DR0: 00000000000000000 DR1: 0000000000000000 DR2: 00000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 00000000000000400

プログラムレジスターの表示

GDB を使用して Linux 32 ビット上の ELF32 実行可能ファイルをデバッグし、info r コマンドを使用してレジスタの状態を確認します。

セグメント レジスタには 0x23 と 0x2b の 2 つのケースがあります。

16進数: 0023
バイナリ: 0000000000100 0 11 - セグメント番号: 4 - テーブルタイプ: GDT - 特権レベル: Ring3
16進数: 002B
バイナリ: 0000000000101 0 11 - セグメント番号: 5 - テーブルタイプ: GDT - 特権レベル: Ring3

セグメント番号: 4ビット目から始まる テーブルタイプ: 3ビット目 特権レベル: 1ビット目と2ビット目

Linux で GDT を直接表示するコマンドやツールが見つからなかったので、ソース コードを調べて答えを見つけました。

これら 2 つの項目によって記述されるセグメントは Windows と同じで、ベース アドレスは 0、サイズは 4 GB です。

Windows と Linux はどちらも、この方法で CPU のセグメント化されたメモリ管理メカニズムをバイパスすることを選択します。

ただし、これは両方のオペレーティング システムに当てはまるものの、セグメント メカニズムが完全に使用されていないことを意味するわけではないことに注意してください。CPU のタスク管理 TSS は引き続き使用する必要があります。誰もがこれを知っておく必要があります。セグメンテーション メカニズムは Linux 64 ビット システムでは歓迎されませんが、オペレーティング システムは引き続き、最初にセグメンテーションを行ってからページングを行うというアドレス指定方法を維持します。

結論

Linux のメモリ管理とアドレス指定に関するこの記事はこれで終わりです。Linux のメモリ管理とアドレス指定の詳細については、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Linuxカーネルのメモリ管理アーキテクチャの詳細な説明
  • Linux のメモリ管理メカニズムの詳細な分析
  • Linux 管理者ガイド (4) -- メモリ管理

<<:  ドラッグ効果を実現するための純粋なCSSコード

>>:  HTML+CSSプロジェクト開発経験概要(推奨)

推薦する

LinuxはMySQLデータベースの自動バックアップとスケジュールバックアップを毎日実装しています

概要バックアップは災害復旧の基礎であり、システム操作エラーやシステム障害によるデータ損失を防ぐために...

CSS3 カスタムスクロールバースタイル::webkit-scrollbar サンプルコード詳細説明

Windows のデフォルトのスクロール バー スタイルは見苦しく、プロジェクト内でスクロール バー...

docker コンペ応募でよく使われるコマンドのまとめ

アカウントにログイン DOCKER_REGISTRY=registry.cn-hangzhou.al...

Mysql通信プロトコルの詳細な説明

1.Mysql接続方法MySQL 通信プロトコルを理解するには、まず MySQL サーバーへの接続に...

Vueはユーザー名が使用可能かどうかの検証を実装します

この記事では、ユーザー名が使用可能かどうかを確認するためのVueの具体的なコードを例として紹介します...

MYSQL(電話番号、IDカード)データ非感応化の実装

1. データ感度低下の説明日常の開発ニーズでは、データの感度低下が頻繁に発生します。たとえば、ID ...

srcまたはcss背景画像のurl値はbase64でエンコードされたコードです

ウェブ上の一部の画像の src または CSS 背景画像 URL の後に、data:image/pn...

MySQL がユーザー名とパスワードの漏洩を引き起こす可能性のある Riddle の脆弱性を公開

MySQL バージョン 5.5 および 5.6 を標的とする Riddle 脆弱性により、中間者攻撃...

リソースアップロード機能を実現するための SpringBoot+nginx の詳細な例

最近、画像、ビデオ、CSS/JS などの静的リソースを配置するために nginx を使用する方法を学...

MySQL の異常なエラー ERROR: 2002 を解決する方法

最近、MySQL の起動中にエラーが発生しました。エラー メッセージは次のとおりです。 エラー 20...

React useMemo と useCallback の使用シナリオ

目次メモを使うコールバックの使用メモを使う親コンポーネントが再レンダリングされると、そのすべての要素...

MySQL マスター/スレーブ データベース同期構成と一般的なエラー

アクセス回数が増えると、時間のかかるデータベース読み取り操作では、データベースへの負荷を軽減するため...

MySQL データベースのバックアップとリカバリの実装コード

データベースのバックアップ #文法: # mysqldump -h server-u usernam...

Docker-compose を使用して ELK クラスターを構築する方法

すべてのオーケストレーション ファイルと構成ファイルは、私の Github からアクセスできます。構...