ホームページ > 記事 > システムチュートリアル > Linux でのメモリ割り当ての仕組み
Linux のメモリ割り当て、特にカーネルとシステム アーキテクチャの詳細を理解することが重要です。 Linux のメモリ割り当てを詳しく調べて、舞台裏で何が起こっているのかを理解しましょう。
コンピュータでプロセスを実行可能にするには、プロセスをメモリに配置する必要があります。これを行うには、メモリ内のプロセスにフィールドを割り当てる必要があります。メモリ割り当ては、特にカーネルとシステム アーキテクチャにおいて注意を払うべき重要な問題です。
Linux のメモリ割り当てを詳しく見て、舞台裏で何が起こっているのかを理解しましょう。
ほとんどのソフトウェア エンジニアは、このプロセスの詳細を知りません。しかし、システムプログラマー候補者であれば、それについてもっと知っておく必要があります。割り当てプロセスを見るときは、Linux と glibc ライブラリについて少し詳しく説明する必要があります。
アプリケーションがメモリを必要とする場合、オペレーティング システムにメモリを要求する必要があります。カーネルからのこのリクエストには当然システム コールが必要です。ユーザーモードでは自分でメモリを割り当てることはできません。
**malloc()** 一連の関数は、C 言語のメモリ割り当てを担当します。ここで尋ねるべき問題は、glibc 関数としての malloc() が直接システム呼び出しを行うかどうかです。
Linux カーネルには malloc と呼ばれるシステム コールはありません。ただし、アプリケーションのメモリ要件には brk と mmap という 2 つのシステム コールがあります。
glibc 関数を通じてアプリケーションのメモリを要求することになるため、現時点で glibc がどのシステム コールを使用しているかを知りたい場合があります。答えは両方です。
各プロセスには連続データ フィールドがあります。 brk システムコールにより、データフィールドの制限を決定するプログラム割り込み値がインクリメントされ、割り当て処理が実行されます。
この方法を使用したメモリの割り当ては非常に高速ですが、未使用の領域をシステムに戻すことが常に可能であるとは限りません。
たとえば、それぞれのサイズが 16KB の 5 つのフィールドを、malloc() 関数を通じて brk システム コールに割り当てるとします。これらのフィールドの 2 番目のフィールドに入力すると、関連リソースをシステムが使用できるように返す (割り当てを解除する) ことができなくなります。 2 番目のフィールドの開始位置を示すためにアドレス値を減らして brk を呼び出すと、3 番目、4 番目、および 5 番目のフィールドの解放が完了するためです。
この場合のメモリ損失を防ぐために、glibc の malloc 実装はプロセス データ フィールド内の割り当てられた場所を監視し、free() 関数で指定されたとおりにシステムにその空き領域を返すため、システムは空き領域を使用できます。さらにメモリを割り当てます。
つまり、16KB 領域を 5 つ確保した後、brk システムコールによるデータ領域の拡張ではなく、free() 関数で 2 番目の領域を返し、しばらくしてからさらに 16KB 領域を要求すると、以前のアドレスに戻りました。
ただし、新たに要求した領域が 16KB を超える場合は、領域 2 が使用できないため、brk システムコールで新たな領域を割り当ててデータ領域を拡張します。領域番号 2 は未使用ですが、サイズが異なるためアプリケーションでは使用できません。このようなシナリオのため、内部断片化と呼ばれる現象が発生し、メモリのすべての部分を実際に完全に利用することがほとんどできなくなります。
理解を深めるために、次のサンプル アプリケーションをコンパイルして実行してみてください:
リーリーアプリケーションを実行すると、次のような出力が表示されます:
リーリーstrace を使用した brk の出力は次のとおりです:
リーリーご覧のとおり、データ フィールドの終了アドレスに 0x21000 が追加されています。これは、値 0x5608595d7000 から理解できます。したがって、約 0x21000、つまり 132KB のメモリが割り当てられます。
ここで考慮すべき点が 2 つあります。 1 つ目は、コード例で指定されている以上の割り当てを行うことです。もう 1 つは、割り当てを提供する brk 呼び出しを引き起こすコード行です。
上記のサンプル アプリケーションを次々に実行すると、毎回異なるアドレス値が表示されます。このようにアドレス空間をランダムに変更すると、セキュリティ攻撃の作業が大幅に複雑になり、ソフトウェアのセキュリティが強化されます。
但是,在 32 位架构中,通常使用 8 位来随机化地址空间。增加位数将不合适,因为剩余位上的可寻址区域将非常低。此外,仅使用 8 位组合不会使攻击者的事情变得足够困难。
另一方面,在 64 位体系结构中,由于可以为 ASLR 操作分配的位太多,因此提供了更大的随机性,并且提高了安全程度。
Linux 内核还支持基于 Android 的设备,并且 ASLR 功能在 Android 4.0.3 及更高版本上完全激活。即使仅出于这个原因,也可以说 64 位智能手机比 32 位版本具有显着的安全优势。
通过使用以下命令暂时禁用 ASLR 功能,之前的测试应用程序每次运行时都会返回相同的地址值:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
要将其恢复到以前的状态,在同一个文件中写入 2 而不是 0 就足够了。
mmap 是 Linux 上用于内存分配的第二个系统调用。通过 mmap 调用,内存中任何区域的空闲空间都映射到调用进程的地址空间。
在以这种方式完成的内存分配中,当您想使用前面 brk 示例中的 free() 函数返回第二个 16KB 分区时,没有机制可以阻止此操作。从进程的地址空间中删除相关的内存段。它被标记为不再使用并返回系统。
因为与使用 brk 相比,使用 mmap 的内存分配非常慢,所以需要分配 brk。
使用 mmap,内存的任何空闲区域都映射到进程的地址空间,因此在该进程完成之前,已分配空间的内容被重置。如果没有以这种方式进行重置,则属于先前使用相关内存区域的进程的数据也可以被下一个不相关的进程访问。这样就不可能谈论系统中的安全性。
内存分配非常重要,尤其是在优化和安全问题上。如上面的示例所示,不完全理解此问题可能意味着破坏系统的安全性。
甚至许多编程语言中存在的类似于 push 和 pop 的概念也是基于内存分配操作的。能够很好地使用和掌握系统内存对于嵌入式系统编程和开发安全和优化的系统架构都是至关重要的。
如果您还想涉足 Linux 内核开发,请考虑首先掌握 C 编程语言。
综上所述,Linux 中的内存分配是一个需要注意和理解的重要问题,特别是对于程序员、内核开发人员和系统架构师而言。熟练掌握内存分配可以提高软件性能和安全性,并在嵌入式系统编程和系统架构方面提供更好的支持。同时,C 编程语言的掌握也是涉足 Linux 内核开发的关键。
以上がLinux でのメモリ割り当ての仕組みの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。