1. ホーム
  2. c++

[解決済み】メモリフラグメンテーションとは何ですか?

2022-04-03 20:03:13

質問

C++の動的メモリ割り当ての文脈で、quot;memory fragmentation"という言葉を何度か耳にしたことがあります。 メモリフラグメンテーションにどう対処するかという質問はいくつか見つかりましたが、それ自体を扱う直接的な質問は見当たりません。 そこで

  • メモリフラグメンテーションとは何ですか?
  • 自分のアプリケーションでメモリの断片化が問題であるかどうかを判断するにはどうしたらよいですか? どのようなプログラムで問題が発生する可能性が高いのでしょうか?
  • メモリフラグメンテーションに対処するための一般的な方法は?

また

  • ダイナミックアロケーションを多用すると、メモリの断片化が進むと聞いたことがあります。 これは本当でしょうか? C++の文脈では、すべての標準コンテナ(std::string, std::vector など)は動的メモリ割り当てを使用すると理解しています。 これらがプログラム全体で使用されている場合(特にstd::string)、メモリの断片化が問題になる可能性は高いでしょうか?
  • STLを多用するアプリケーションでは、メモリの断片化にどのように対処すればよいですか?

どのように解決するのですか?

大きな(32バイト)空きメモリがあると想像してください。

----------------------------------
|                                |
----------------------------------

では、その一部をアロケートしてください(5回アロケート)。

----------------------------------
|aaaabbccccccddeeee              |
----------------------------------

さて、最初の4つのアロケーションを解放しますが、5つ目は解放しないでください。

----------------------------------
|              eeee              |
----------------------------------

では、16バイトを割り当ててみてください。おっと、その倍近い空き容量があるのに、できませんね。

仮想メモリを使用するシステムでは、断片化は思ったより問題ではありません。 仮想 アドレス空間ではなく 物理的 のアドレス空間です。ですから、この例では、ページサイズ2バイトの仮想メモリがあれば、16バイトの割り当てを問題なく行うことができます。物理メモリは次のようになります。

----------------------------------
|ffffffffffffffeeeeff            |
----------------------------------

一方、仮想メモリは(もっと大きいので)次のようになります。

------------------------------------------------------...
|              eeeeffffffffffffffff                   
------------------------------------------------------...

メモリの断片化の典型的な症状は、十分なメモリの空きがあるように見えるのに、大きなブロックを割り当てようとすると割り当てられないというものです。もうひとつ考えられるのは、プロセスがOSにメモリを解放し返せないことです(なぜなら、OSから割り当てた大きなブロックのそれぞれは、たとえば malloc などを小分けにするために、各ブロックのほとんどが未使用であるにもかかわらず、何かが残っています)。

C++でメモリの断片化を防ぐ戦術は、サイズや予想される寿命に応じて、異なる領域からオブジェクトを割り当てることで機能します。つまり、たくさんのオブジェクトを作成して、後でまとめて破棄する場合は、メモリプールから割り当てます。オブジェクトとオブジェクトの間にある他のオブジェクトの割り当てはプールから行われないので、メモリ上でオブジェクトとオブジェクトの間に位置することはなく、結果としてメモリは断片化されません。また、同じサイズのオブジェクトをたくさん割り当てるのであれば、同じプールから割り当てます。そうすれば、プール内の空き領域は、そのプールから割り当てようとするサイズより小さくなることはありません。

一般的には、プログラムが長時間動作し、割り当てと解放が大量に行われない限り、あまり気にする必要はないでしょう。最も危険なのは、短命のオブジェクトと長命のオブジェクトが混在している場合ですが、そのような場合でも malloc は最善を尽くしてくれます。基本的には、プログラムが割り当てに失敗したり、予期せずシステムのメモリが不足したりするまでは、無視してください (優先順位としては、テスト時にこれをキャッチしてください!)。

標準ライブラリは、メモリ割り当てを行う他のどのようなものよりも悪くありませんし、標準コンテナにはすべて Alloc テンプレート・パラメータを使用することで、必要であれば、割り当て戦略を微調整することができます。