Linux のメモリ割り当て戦略を 1 つの記事で理解する
Linux プロセスのメモリ配分はどのようになりますか?
Linux オペレーティング システムでは、仮想アドレス空間の内部は カーネル空間とユーザー空間に分割されており、桁が異なるシステムではアドレス空間の範囲も異なります。たとえば、最も一般的な 32 ビット システムと 64 ビット システムは次のとおりです。

ここから見ることができます:
- 32 ビット システムのカーネル空間は最上位の 1G を占め、残りの 3G はユーザー空間です。
- 64 ビット システムのカーネル空間とユーザー空間は両方とも 128T で、それぞれメモリ空間全体の最高位と最低位の部分を占め、残りの中間部分は未定義です。
カーネル空間とユーザー空間の違いについて話しましょう:
- プロセスがユーザー モードの場合、プロセスはユーザー空間メモリにのみアクセスできます;
- カーネル状態に入った後にのみ、カーネル空間内のメモリにアクセスできます;
各プロセスには独自の独立した仮想メモリがありますが、各仮想メモリ内のカーネル アドレスは実際には同じ物理メモリに関連付けられています。このようにして、プロセスがカーネル状態に切り替わった後、カーネル空間メモリに簡単にアクセスできます。

次に、仮想空間の分割について詳しく学びましょう。ユーザー空間とカーネル空間はさまざまな方法で分割されます。カーネル空間の配分については多くは語りません。
ユーザー空間の分布を見てみましょう。32 ビット システムを例として、それらの関係を示す図を描きました。
この図から、ユーザー空間メモリが低位から高位まで 6 つの異なるメモリ セグメントに分割されていることがわかります。:

- 初期化されたデータ セグメント (静的定数を含む);
- 未初期化の静的変数を含む、初期化されていないデータ セグメント;
- 動的に割り当てられたメモリを含むヒープ セグメントは、下位アドレスから始まり、上に向かって増加します。 ダイナミック ライブラリ、共有メモリなどを含むファイル マッピング セグメントは、低いアドレスから始まり、上に向かって増加します (ハードウェアとカーネルのバージョンに応じて);
- ローカル変数や関数呼び出しコンテキストなどを含むスタック セグメント。スタック サイズは固定で、通常は 8 MB です。もちろん、システムはサイズをカスタマイズできるパラメーターも提供します;
- これら 6 つのメモリ セグメントのうち、ヒープ セグメントとファイル マッピング セグメントのメモリは動的に割り当てられます。たとえば、C 標準ライブラリの malloc() または mmap() を使用すると、それぞれヒープ セグメントとファイル マッピング セグメントにメモリを動的に割り当てることができます。
実際には、malloc() はシステム コールではなく、メモリを動的に割り当てるための C ライブラリ内の関数です。 malloc メモリを申請する場合、オペレーティング システムからヒープ メモリを申請するには 2 つの方法があります。
方法 1: brk() システム コールを通じてヒープからメモリを割り当てる-
方法 2: mmap() システム コールを通じてファイル マッピング領域にメモリを割り当てます;
- 方法 1 の実装は非常に簡単です。brk() 関数を使用して「ヒープの最上位」ポインタを上位アドレスに移動し、新しいメモリ空間を取得します。以下に示すように:
ユーザーが割り当てたメモリが 128 KB 未満の場合は、brk();#「」
malloc() はどのような状況で brk() を通じてメモリを割り当てますか? mmap() を通じてメモリが割り当てられるのはどのようなシナリオですか?
」
#malloc() には、ソース コードでデフォルトで定義されたしきい値があります:
- を通じてメモリを申請します。 ユーザーが割り当てたメモリが 128 KB を超える場合は、mmap();
- を通じてメモリを申請します。 glibc のバージョンが異なると、定義されるしきい値も異なることに注意してください。
malloc() は物理メモリを割り当てますか?
いいえ、
malloc() は仮想メモリを割り当てます。 割り当てられた仮想メモリにアクセスしない場合、仮想メモリは物理メモリにマッピングされないため、物理メモリを占有しません。
割り当てられた仮想アドレス空間にアクセスする場合のみ、オペレーティング システムはページ テーブルを検索し、仮想メモリに対応するページが物理メモリにないことを検出し、ページ フォールト割り込みをトリガーし、オペレーティング システムは仮想メモリと物理メモリ、メモリ間のマッピング関係を確立します。
malloc(1) はどのくらいの仮想メモリを割り当てますか?malloc() がメモリを割り当てるとき、ユーザーが期待するバイト数に応じてメモリ空間を割り当てるのではなく、
はより大きな空間をメモリ プールとして事前に割り当てます。 事前に割り当てられる特定のスペースの量は、malloc によって使用されるメモリ マネージャーに関連しています。分析には、malloc のデフォルトのメモリ マネージャー (Ptmalloc2) を使用します。
次に、次のコードを使用して実験を行い、malloc を通じて 1 バイトのメモリを申請したときにオペレーティング システムによって実際に割り当てられるメモリ領域の量を確認してみましょう。
リーリー実行コード (
使用する glibc ライブラリのバージョンが 2.17であることを事前に説明しておきます):
/proc//maps ファイルを通じてプロセスのメモリ分布を確認できます。この 1 バイトのメモリ開始アドレスによって、マップ ファイル内のメモリ アドレスの範囲をフィルタリングします。
この例で割り当てられたメモリは 128 KB 未満であるため、メモリは brk() システム コールを通じてヒープ領域に適用され、右端に [heap] マークが表示されます。
ご覧のとおり、ヒープ領域のメモリ アドレス範囲は 00d73000 ~ 00d94000 で、この範囲のサイズは 132KB です。これは、
malloc(1) が実際に 132K バイトのメモリを事前に割り当てることを意味します## #。一部の学生は、プログラムで出力されたメモリの開始アドレスが d73010 であり、マップ ファイルではヒープ メモリ空間の開始アドレスが d73000 であることに気づいたかもしれません。なぜ余分な 0x10 (16 バイト) があるのでしょうか?この質問は今は脇に置いておいて、後で説明します。
#free はメモリを解放してオペレーティング システムに戻しますか?free() 関数でメモリを解放した後、上記のプロセスを実行してヒープ メモリがまだあるかどうかを確認してみましょう。
下の図からわかるように、メモリを解放した後もヒープ メモリはまだ存在しており、オペレーティング システムに返されていません。

これは、この 1 バイトをオペレーティング システムに解放するのではなく、キャッシュして malloc のメモリ プールに入れる方が良いためです。プロセスが 1 バイトのメモリを再度適用すると、この速度ははるかに高速です。

上記の空きメモリは、brk() メソッドを介して malloc によって適用されたメモリ用であり、ヒープ メモリはまだ存在します。
malloc が mmap を通じてメモリに適用された場合、free がメモリを解放した後、メモリがオペレーティング システムに返されます。
malloc を通じて 128 KB のメモリを申請し、malloc が mmap を通じてメモリを割り当てることを検証する実験を行ってみましょう。
リーリー
実行コード:プロセスのメモリ分布を見ると、右端に[先頭]マークがなく、ファイルマッピング領域からmmap経由で匿名マッピングにより匿名メモリが割り当てられていることがわかります。

それでは、このメモリを解放して見てみましょう:

128 KB メモリの開始アドレスを再度確認すると、メモリがもう存在していないことがわかり、オペレーティング システムに返されたことがわかります。

「malloc によって要求され、free によって解放されたメモリはオペレーティング システムに返されますか?」という質問については、次のように要約できます。
-
malloc が
- brk() を通じてメモリを適用し、free がメモリを解放すると、 はメモリをオペレーティング システムに返さず、次回使用されるまで malloc のメモリ プールにキャッシュします; free が
- mmap() を通じて malloc によって割り当てられたメモリを解放すると、 はメモリをオペレーティング システムに返し、メモリは実際に解放されます 。
メモリ割り当てに mmap を使用しないのはなぜでしょうか?
OSからのメモリの申請にはシステムコールが必要なため、システムコールを実行するにはカーネル状態に入り、その後ユーザー状態に戻る必要があり、実行状態への切り替えに時間がかかります。したがって、メモリを確保する操作は頻繁にシステム コールを行わないようにする必要があり、mmap を使用してメモリを確保すると、毎回システム コールを実行する必要があります。
また、mmap によって割り当てられたメモリは解放されるたびにオペレーティング システムに返されるため、mmap によって割り当てられた仮想アドレスは毎回ページ フォールト状態になり、仮想アドレスにアクセスするたびにページ フォルト状態になります。初めて、ページフォルト割り込みがトリガーされます。
つまり、
mmapで確保したメモリを頻繁に使用すると、その都度実行状態が切り替わるだけでなく、(仮想アドレスへの最初のアクセス後)ページフォルト割り込みも発生します。これにより CPU が消費されます。 が大きいほど。
これら 2 つの問題を改善するために、malloc が brk() システム コールを通じてヒープ領域のメモリに適用するとき、ヒープ領域は連続しているため、より大きなメモリをメモリ プールとして直接事前に割り当てます。解放されると、メモリ プールにキャッシュされます。
次回メモリを申請する際には、該当するメモリブロックをメモリプールから直接取り出すだけで、このメモリブロックの仮想アドレスと物理アドレスのマッピング関係が残っている可能性があります。システムの削減 呼び出しの数により、ページ フォールト割り込みの数も削減され、CPU 消費量が大幅に削減されます。
brk は非常に素晴らしいので、すべての割り当てに brk を使用してみてはいかがでしょうか?brk を通じてヒープ領域から割り当てられたメモリはオペレーティング システムに返されないことを前述したため、そのようなシナリオを考えてみましょう。
10k、20k、30k の 3 つのメモリを連続して申請した場合、10k と 20k が解放されると空きメモリ領域になります。次回申請されるメモリが 30k 未満であれば、この空きメモリは使用できます。再利用できるスペース。
しかし、次回要求されるメモリが 30k を超える場合は、空きメモリ容量がなくなり、OS に申請する必要があり、実際に使用されるメモリは増加し続けます。
したがって、システムが特に小さなメモリ ブロックに対して頻繁にマロックと解放を行うと、ヒープ内に使用できないフラグメントがどんどん生成され、「メモリ リーク」が発生します。この「漏れ」現象は、valgrind では検出できません。
したがって、malloc の実装では、brk と mmap の動作の違い、利点、欠点が十分に考慮され、mmap がメモリ空間を割り当てる前に、デフォルトで大きなメモリ ブロック (128KB) が割り当てられます。
free() 関数はメモリ アドレスのみを渡しますが、解放すべきメモリの量を知ることができるのはなぜでしょうか?
malloc によってユーザー モードに返されるメモリの開始アドレスは、プロセスのヒープ領域の開始アドレスより 16 バイト大きいと前に述べたことを覚えていますか?
追加の 16 バイトには、メモリ ブロックのサイズなど、メモリ ブロックの説明情報が格納されます。

このようにして、free() 関数が実行されると、free は受信したメモリ アドレスを 16 バイト左にオフセットし、この 16 バイトから現在のメモリ ブロック サイズを分析します。どれだけのメモリを解放するか。
以上がLinux のメモリ割り当て戦略を 1 つの記事で理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











VSコードシステムの要件:オペレーティングシステム:オペレーティングシステム:Windows 10以降、MACOS 10.12以上、Linux Distributionプロセッサ:最小1.6 GHz、推奨2.0 GHz以上のメモリ:最小512 MB、推奨4 GB以上のストレージスペース:最低250 MB以上:その他の要件を推奨:安定ネットワーク接続、XORG/WAYLAND(Linux)

VSコード拡張機能のインストールの理由は、ネットワークの不安定性、許可不足、システム互換性の問題、VSコードバージョンが古すぎる、ウイルス対策ソフトウェアまたはファイアウォール干渉です。ネットワーク接続、許可、ログファイル、およびコードの更新、セキュリティソフトウェアの無効化、およびコードまたはコンピューターの再起動を確認することにより、問題を徐々にトラブルシューティングと解決できます。

NotePadはJavaコードを直接実行することはできませんが、他のツールを使用することで実現できます。コマンドラインコンパイラ(Javac)を使用してByteCodeファイル(filename.class)を生成します。 Javaインタープリター(Java)を使用して、バイトコードを解釈し、コードを実行し、結果を出力します。

VSコードは、Microsoftが開発した無料のオープンソースクロスプラットフォームコードエディターと開発環境であるフルネームVisual Studioコードです。幅広いプログラミング言語をサポートし、構文の強調表示、コード自動完了、コードスニペット、および開発効率を向上させるスマートプロンプトを提供します。リッチな拡張エコシステムを通じて、ユーザーは、デバッガー、コードフォーマットツール、GIT統合など、特定のニーズや言語に拡張機能を追加できます。 VSコードには、コードのバグをすばやく見つけて解決するのに役立つ直感的なデバッガーも含まれています。

VSコードはMacで利用できます。強力な拡張機能、GIT統合、ターミナル、デバッガーがあり、豊富なセットアップオプションも提供しています。ただし、特に大規模なプロジェクトまたは非常に専門的な開発の場合、コードと機能的な制限がある場合があります。

Visual Studio Code(VSCODE)は、Microsoftが開発したクロスプラットフォーム、オープンソース、および無料のコードエディターです。軽量、スケーラビリティ、および幅広いプログラミング言語のサポートで知られています。 VSCODEをインストールするには、公式Webサイトにアクセスして、インストーラーをダウンロードして実行してください。 VSCODEを使用する場合、新しいプロジェクトを作成し、コードを編集し、コードをデバッグし、プロジェクトをナビゲートし、VSCODEを展開し、設定を管理できます。 VSCODEは、Windows、MacOS、Linuxで利用でき、複数のプログラミング言語をサポートし、マーケットプレイスを通じてさまざまな拡張機能を提供します。その利点には、軽量、スケーラビリティ、広範な言語サポート、豊富な機能とバージョンが含まれます

Linuxの主な用途には、1。Serverオペレーティングシステム、2。EmbeddedSystem、3。Desktopオペレーティングシステム、4。開発およびテスト環境。 Linuxはこれらの分野で優れており、安定性、セキュリティ、効率的な開発ツールを提供します。

gitリポジトリアドレスを表示するには、次の手順を実行します。1。コマンドラインを開き、リポジトリディレクトリに移動します。 2。「git remote -v」コマンドを実行します。 3.出力と対応するアドレスでリポジトリ名を表示します。
