Linuxメモリ管理の最適化

一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して18日目です。クリックしてイベントの詳細をご覧ください

ファイルマッピング

ファイルマッピングは、仮想メモリをマッピングすることで実装されます。マッピングする場合、プロセスは実際にファイルに対応するコピーの仮想メモリアドレスにアクセスします。仮想メモリの場所にアクセスすると、ファイルの変更とマッピングを完了してから、物理メモリに直接アクセスできます。実際のメモリ変更内容です。また可能です。

一般:ファイルの特定のアドレスがわかっている場合は、メモリアドレスを直接見つけて、コンテンツを上書きすることもできます。

ページネーションをリクエストする

カーネルにメモリを適用するプロセスは、ページングを要求することによって行われます。前述のように、mmapによってメモリを適用する方法は非常に便利であり、2つの一般的なメモリ割り当て方法があります。

  • 物理メモリの直接適用と割り当て、効率的
  • ハンドルが割り当てられる方法、つまりページテーブルは、プロセスに渡す前に仮想メモリと実際のメモリにマップされます

これらの2つの割り当て方法には、2つの明らかな問題があります。つまり、割り当てが適用されても使用されない場合、多くの無駄が発生します。さらに、glibcは一度にプロセスのメモリを超える必要があり、大規模なプロセス管理になります。未使用のメモリを割り当てます。

リクエストのページングをよりよく理解するには、ページングの3つの状態を理解する必要があります。

  • ページテーブルと物理メモリはプロセスに割り当てられません。
  • ページテーブルは割り当てられますが、物理メモリは割り当てられません。
  • ページテーブルと物理メモリが割り当てられます。

割り当ての無駄の問題を解決するために、プロセスのメモリは1回だけ割り当てられます。ページングを要求するコアは、カーネルページフォールト割り込みのメカニズムを使用することです。プロセスが最初に割り当てられたスペースにアクセスするとき、この時点では、カーネルに物理メモリは割り当てられていません。ページフォールト割り込み処理が実行されると同時に、プロセスは実際に物理メモリを割り当てに適用します。これにより、各メモリ割り当てが有効になります。

この方法も遅延読み込み方法に似ています。つまり、割り当てアクションの実行が保証され、ページフォールトの中断を検出せずにプロセスを正常に実行できます。

如果使用C语言按照请求分页的特点进行实验可以发现当内存没有使用的时候即使显示已经分配内存,但是实际可用物理内存没有变动。另外分配内存失败分为虚拟内存分配失败,物理内存分配失败,这是因为懒加载的设计导致的,另外虚拟内存不足不一定会导致物理内存不足,因为只要可用物理在分配时刻小于虚拟内存,那就是没法分配。

写时复制

写时复制是利用fork的函数提高虚拟内存分配效率,在文件系统的体现是update或者delete不会动原数据,而是用副本完成操作,当操作完成再更新引用,如果中间宕机断电,则用日志恢复状态即可。

在 Linux 系统的内存管理中调用 fork 系统调用创建子进程时,并不会把父进程所有占用的内存页复制一份,而是首先与父进程共用相同的页表,而当子进程或者父进程对内存页进行修改时才会进行复制 —— 这就是著名的 写时复制 机制。

写时复制的流程如下:

  • 在父进程调用fork的时候,并不是把所有内存复制给子进程 而是递交自己的页表给子进程。完成这一步如果子父进程只进行只读操作双方都会共享页表,但是一旦一方要改变数据,就会立马解除共享。
  • 在解除共享的时候会有如下操作
    • 由于写入失去权限,所以会出发缺页中断
    • 内核干预,执行缺页中断
    • 写入方的数据复制到另一处,并且把写入方的页表全部更新为新复制的内存并且赋予写入方写入权限,同时把之前共享的页表更新。而另一方则把这个刷新之后的页表重新连接即可。
    • 最后父子进程彻底写入权限和页表独立。但是之前解除共享的页表依然可以自由读写。

注意:fork调用的时候:并不会复制页表和内容,而是真正写入的时候会触发复制动作,这也是写时复制名字由来

交换内存

交换内存是Linux内核一种oom情况下的补偿机制,作用也是为了缓解内存溢出和不足的问题,交换内存的实现依靠的是虚拟内存的机制。 简单理解就是在物理内存虽然不够,但是虚拟内存可以借用外部存储器也就是硬盘的一部分空间来充当物理内存使用,这一块分区叫做交换区,由于是借物理存储空间,这个操作也叫做换出。 另外如果借用的空间被释放则归还,这部分操作叫做换入,由于交换内存以页为单位,部分资料也叫页面调入和调出,都是一个意思。

成这一步如果只进行只读操作双方都会共享页表,但是一旦一方要改变数据,就会立马解除共享。

  • 在解除共享的时候会有如下操作
    • 由于写入失去权限,所以会出发缺页中断
    • 内核干预,执行缺页中断
    • 写入方的数据复制到另一处,并且把写入方的页表全部更新为新复制的内存并且赋予写入方写入权限,同时把之前共享的页表更新。而另一方则把这个刷新之后的页表重新连接即可。
    • 最后父子进程彻底写入权限和页表独立。但是之前解除共享的页表依然可以自由读写。

注意:fork调用的时候:并不会复制页表和内容,而是真正写入的时候会触发复制动作,这也是写时复制名字由来

另外交换内存很容易认为是一种扩充物理内存的美好方式,但是这里有一个本质的问题,那就是硬盘的访问速度和内存相比差的次方级别的差距。另外如果长期内存不足很容易导致交换内存不断的换入换出出现明显的性能抖动。

另外这类需要外部存储器的缺页中断在术语中被称之为硬性页缺失,相对的不需要外部存储器的页缺失是软性页缺失,虽然本质都是内核在触发和完整操作,但是硬性的缺失总归比软性缺失后果严重很多。

这里也要吐槽一下M1的各种偷硬盘缓存来提高性能的操作.....

多级页表

多级页表的设计核心是:避免把全部页表一直保存在内存中是多级页表的关键所在。特别是那些不需要的页表就不应该保留。

在X86-64架构当中,虚拟地址的空间大小约为128T,一个页的大小为4KB,页表的项目大小为8个字节。

所以一个进程的页表至少需要256GB内存!(8 * 128T / 4KB),但是我们都知道现在的电脑一般都是16GB内存为主,而32GB的内存虽然但是个人用的比较少。 那么系统应该如何维护页表?这就引入了多层页表来进行管理,多集页表可以从最简单的角度当作一个多级的指针看待,当然实际的多级页表一两句话是说不完的,这里我们可以大致理解多级页表是如何提升性能的?

首先我们可以思考,一个进程是否需要整个页表来管理内存?很显然是不需要的,这是引入多级页表的理由之一,可以发现绝大多数都不需要,比如一个进程需要12M空间,顶端需要4M,数据部分占用4M,底部又是一些堆栈内容和记录信息,在数据顶端上方和堆栈之间是大量根本没有使用的空闲区。

所以多级页表实际上就是大目录套小目录,和我们的一本书一样,小目录负责小的进程,而遇到比较大的进程就放到空闲页比较大的目录中完成分配操作,多级页表既可以高效的利用内存的同时,可以最大限度的减少页表本身的数据结构在内存的占用,同时上面的例子也可以发现绝大多数的进程其实根本不需要太大的页表进行维护和管理。

最后从网上的资料翻阅中发现一张下面的图,对于多级页表的理解有一定帮助:

最后X86_64 使用了4层的页表结构,直当理解就是四级指针,复杂程度可见一般。

标准大页

随着进程虚拟内存和页表的使用,进程使用的物理内存也会增加。

我们根据请求分页和写时复制的概念,可以发现当进程使用虚拟内存量增加会有一个明显的问题那就是在调用fork函数的时候会对于父子进程共享的页表进行拷贝,虽然这个拷贝动作不会占用物理内存,但是为进程复制操作需要拷贝一份完整的页表,所以当页表很大的时候,也会造成性能浪费。

为了解决这个问题,Linux提供了标准大页的机制,和他名字一样,就是比普通的页表更大的页,利用这种页表可以减小进程页表所需的内存使用量。

さらに、第2レベルのページテーブルと標準のラージテーブルは、ページテーブルエントリ全体の数を効果的に減らすことができます。最後に、標準のラージページの場合、標準のラージページが多数のページテーブルのオーバーヘッドを減らすことができることを知っておく必要があります。仮想メモリプロセスの。

使用法

C言語では、mmap関数パラメーターを使用してMAP_HUGETLBフラグを指定し、巨大なページを取得できることを示しますが、より一般的な方法は、この手動切り替え方法の代わりに、プログラムを使用して標準の叔父を使用できるようにすることです。

仮想マシンやデータベースなど、大量のメモリを必要とするアプリケーションには標準の巨大ページが必要です。標準の巨大ページを使用するかどうかは、実際の状況に応じて決定されます。この設定により、このタイプのソフトウェアのメモリ使用量を削減し、フォークを改善できます。効率。。

透明な巨大ページ透明な巨大ページは、標準の巨大ページに付随する機能です。主な機能は、連続する4KBページが指定された条件を満たす場合、透明な巨大ページメカニズムによって標準の巨大ページに変換できることです。条件が満たされると、大きなページは複数の4KBページに分割されるため、このメカニズム

まとめ

このパートでは、Linuxの2つの重要なメカニズムをファイルマッピングのコンテンツから拡張します。リクエストページングコピーオンライトです。目的はプロセスによるメモリの浪費を最小限に抑えることですが、これら2つの方法ではカーネルを使用することに注意してください。モードのシステム割り込みメカニズムが処理されるため、カーネルのパフォーマンスと安定性の要件は非常に高くなります。

次のコンテンツでは、スワップメモリ​​、マルチレベルページテーブル、および標準の巨大ページを紹介します。マルチレベルページテーブルの内部の詳細は非常に複雑です。通常、オペレーティングシステムの最下層に精通している必要があります。これを理解してください。ページテーブルの詳細。

おすすめ

転載: juejin.im/post/7088686036653604878