質問

メモリの割り当てと割り当て解除が頻繁に行われる、寿命の長いアプリケーションがあります。malloc 実装では、解放されたメモリがシステムに戻されますか?

この点で、次の動作はどうなるでしょうか。

  • ptmalloc 1、2 (glibc デフォルト) または 3
  • dlmalloc
  • tcmalloc (Google スレッドの malloc)
  • Solaris 10-11 のデフォルトの malloc および mtmalloc
  • FreeBSD 8 のデフォルトの malloc (jemalloc)
  • マロックを蓄えますか?

アップデート

昼と夜でメモリ消費量が大きく異なるアプリケーションがある場合(例)、解放されたメモリをシステムに返すように malloc を強制できますか?

このようなリターンがなければ、解放されたメモリは何度もスワップアウトおよびスワップインされますが、そのようなメモリにはゴミしか含まれません。

役に立ちましたか?

解決

次の分析は、glibc (ptmalloc2 アルゴリズムに基づく) にのみ適用されます。解放されたメモリをシステムに戻すのに役立つと思われる特定のオプションがあります。

  1. mallopt() (で定義されています) malloc.h) パラメータ オプションの 1 つを使用してトリムしきい値を設定するオプションが提供されます。 M_TRIM_THRESHOLD, 、これは、データ セグメントの先頭で許可される空きメモリの最小量 (バイト単位) を示します。量がこのしきい値を下回る場合、glibc は brk() カーネルにメモリを返します。

    のデフォルト値 M_TRIM_THRESHOLD Linux では 128K に設定されているため、より小さい値を設定するとスペースを節約できる可能性があります。

    環境変数にトリムしきい値を設定することで、同じ動作を実現できます。 MALLOC_TRIM_THRESHOLD_, 、ソースの変更は一切ありません。

    ただし、予備テスト プログラムは次を使用して実行されます。 M_TRIM_THRESHOLD malloc によって割り当てられたメモリがシステムに返されたとしても、メモリの実際のチャンク (アリーナ) の残りの部分は最初に要求されたものであることがわかりました。 brk() 保持される傾向があります。

  2. を呼び出すことで、メモリ領域をトリミングし、未使用のメモリをシステムに戻すことができます。 malloc_trim(pad) (で定義されています) malloc.h)。この関数はデータ セグメントのサイズを変更し、少なくとも pad バイトが末尾にあり、解放できるバイトが 1 ページに満たない場合は失敗します。セグメント サイズは常に 1 ページの倍数で、i386 では 4,096 バイトです。

    この変更された動作の実装は、 free() を使用して malloc_trim これは、malloc フック機能を使用して実行できます。これには、コアの glibc ライブラリに対するソース コードの変更は必要ありません。

  3. を使用して madvise() glibc の無料実装内のシステム コール。

他のヒント

ほとんどの実装では、(OSに合ったどんな大きさの)全体の「ブロック」が解放されたと返されたが、もちろん例外であることができ、それらの(比較的まれな)ケースを特定する気にしないでください。例えば、私は、OpenBSDで Wikipediaのページ、から引用:

  

freeへの呼び出しでは、メモリが解放されます   そして、プロセスのアドレスからマップされていません   munmapを使用した空間。このシステムは、   取ることによって、セキュリティを向上させるために設計されました   アドレス空間レイアウトの利点   ランダム化およびギャップページの機能   OpenBSDのmmapの一部として実装   システムコール、および検出するために、   使用-後フリーのバグ-として大容量メモリ   割り当ては完全にマッピングされていません   それが解放された後、さらに原因を使用   セグメンテーションフォールトと終了   プログラムのます。

ほとんどのシステムは、しかし、セキュリティに重点を置いたのOpenBSDなどとしてではありません。

私は大量のメモリのための既知のツーも一時要件があり、長時間実行システムをコーディングしていたとき、私は常にプロセスをforkしようとし、これを知っている:親はその後、ちょうどからの結果を待ち子供は[典型的には、パイプ上]、子供が(メモリ割り当てを含む)の計算を行い、[パイプ]前記の[]の結果を返し、その後、終了します。このように、私の長時間実行プロセスは、メモリのためにその需要が時折「スパイク」の間に長い時間の間、メモリを占有無駄ではありません。他の代替戦略は、このような特殊な要件(下JavaやPythonなどの仮想マシンを持つ言語は通常ないのにC ++は、それが合理的に容易になります)用のカスタムメモリアロケータへの切り替えを含めます。

OPと同じ問題に対処しています。今のところ、tcmalloc を使用すれば可能のようです。2 つの解決策を見つけました。

  1. tcmalloc をリンクしてプログラムをコンパイルし、次のように起動します。

    env TCMALLOC_RELEASE=100 ./my_pthread_soft
    

    文書 と言及しています

    適切なレートは [0,10] の範囲内です。

    しかし、10 では私には十分ではないようです (つまり、変化が見られません)。

  2. コード内で、解放されたメモリをすべて解放すると興味深い場所を見つけて、次のコードを追加します。

    #include "google/malloc_extension_c.h" // C include
    #include "google/malloc_extension.h"   // C++ include
    
    /* ... */
    
    MallocExtension_ReleaseFreeMemory();
    

私の場合、2 番目の解決策は非常に効果的でした。最初のものは素晴らしいですが、あまり成功しません。たとえば、適切な数値を見つけるのが複雑です。

私はいくつかの調査の後、私は割り当てられたオブジェクトが(未満120のバイト私の場合には)小さい場合、何らかの理由でglibcのは、システムにメモリを返さないことに気づいた、私のアプリで同様の問題があった。
このコードを見てください:  

#include <list>
#include <malloc.h>

template<size_t s> class x{char x[s];};

int main(int argc,char** argv){
    typedef x<100> X;

    std::list<X> lx;
    for(size_t i = 0; i < 500000;++i){
        lx.push_back(X());
    }

    lx.clear();
    malloc_stats();

    return 0;
}

プログラムの出力:

Arena 0:
system bytes     =   64069632
in use bytes     =          0
Total (incl. mmap):
system bytes     =   64069632
in use bytes     =          0
max mmap regions =          0
max mmap bytes   =          0

約64 MBのシステムに戻るされていません。 :私はへのtypedef変更した場合 typedef x<110> X;プログラムの出力は次のようになります:

Arena 0:
system bytes     =     135168
in use bytes     =          0
Total (incl. mmap):
system bytes     =     135168
in use bytes     =          0
max mmap regions =          0
max mmap bytes   =          0

ほぼすべてのメモリが解放されました。私はまた、いずれの場合もmalloc_trim(0)を使用すると、システムにメモリを解放ことに気づいた。
ここでの出力は、上記コードにmalloc_trimを追加した後である

Arena 0:
system bytes     =       4096
in use bytes     =          0
Total (incl. mmap):
system bytes     =       4096
in use bytes     =          0
max mmap regions =          0
max mmap bytes   =          0

あなたが言及したものも含め、すべての「通常の」mallocを、のために、メモリがなく、バックシステム全体に、あなたのプロセスで再利用するためにリリースされます。バックシステム全体に解放すると、あなたのプロセスが最終的に終了されている場合にのみ起こります。

を一覧表示するもののうち、唯一の買いだめは、メモリをシステムに戻ります...しかし、それは実際に行うことができれば、それはあなたのプログラムの割り当ての動作に多くを依存します。

短い答え:(malloc_trimを使用し、OSにメモリを返却するのmallocサブシステムを強制的に)。それ以外の場合は、メモリを返すの動作は実装に依存します。

FreeBSD 12 malloc(3) 用途 ジェマロック 5.1 は、解放されたメモリ (「ダーティ ページ」) を OS に返します。 madvise(...MADV_FREE).

解放されたメモリは、によって制御される時間遅延の後にのみ返されます。 opt.dirty_decay_ms そして opt.muzzy_decay_ms;を見てください マニュアルページ この 減衰ベースの未使用ダーティ ページ パージの実装に関する問題 詳細については。

FreeBSD の以前のバージョンには、古いバージョンの jemalloc が同梱されており、これも解放されたメモリを返しますが、何をいつパージするかを決定するために異なるアルゴリズムを使用します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top