2017-01-31 14 views
4

2つのスレッドを実行し、小さな配列(〜4096バイト)をソートして出力ファイルに書き込む単純なプログラムを作成しました。入力データには1つの大きなファイル(〜4Gb)が含まれています。コンピュータには128MBのメモリがあります。私は空のメイン関数を実行すると14MBのメモリを使用することが分かった。空の関数アプリケーションでstd :: threadを実行すると、スレッドごとに〜8MBが使用され始めます。しかし、私は1つの動的メモリ割り当てプログラムを作成する場合は、スレッドあたり約64MBを使用し始めます。私は何がそんなにメモリを費やすことができるのか分かりません。どのようにこのサイズを制御できますか?システムのデフォルト割り当てを最小限に抑えるためにダイナミックメモリをどのように割り当てるか?空の関数を使ってstd :: threadを実行すると、大量のメモリが必要になる

  • システム:のUbuntu 14.04.3
  • コンパイラ:のgcc 4.8.4
  • コンパイラオプション: '-std = C++ 11 -03 -pthread'

  • これはコード例です

    void dummy(void) 
    { 
        std::vector<unsigned int> g(1); 
        int i = 0; 
        while(i<500000000) 
        { 
         ++i; 
        } 
    } 
    
    int main(void) 
    { 
        std::thread t1(&dummy); 
        std::thread t2(&dummy); 
        std::thread t3(&dummy); 
        t1.join(); 
        t2.join(); 
        t3.join(); 
        return 0; 
    } 
    
+0

異なるアロケータを試してみてください。 jemalloc、tcmalloc。 –

+2

プログラムで使用したメモリの量はどのように決定しましたか? –

+1

私はあなたの措置を信用していません。どのようにしてメモリフットプリントを見つけましたか? – SergeyA

答えて

7

すべてのスレッドには独自のスタックがあります。 Linuxでは、デフォルトのスタックサイズは8 MBです。初めてメモリを割り当て始めると、ヒープメモリアロケータは実際に大きなチャンクを予約することがあります。これはかもしれないはあなたが見ているスレッドごとの64MBを説明します。

つまり、「割り当て済み」と言えば、このメモリが実際に使用されているわけではありません。割り当てはプロセスの仮想メモリ空​​間で行われます。 psを実行した場合はVSZtopを実行した場合はVIRTの列に表示されます。しかし、Linuxは、とにかくその割り当てられたメモリのほとんどを使用するつもりはないことを知っています。したがって、仮想ブロックのメモリを割り当てている間、Linuxはプロセスが実際にそのメモリへの書き込みを開始するまで、物理的なメモリを割り当てません。プロセスによって使用される実際の物理量はpsの場合はRSStopの場合はRESになります。 Linuxでは、物理メモリよりも多くの仮想メモリを割り当てることができます。

物理的なのメモリが使い果たされないかもしれませんが、それぞれが8 MBの仮想メモリを割り当てる32ビットシステムに多数のスレッドを持っている場合、仮想メモリプロセスのスペース(2 GB程度) C++のスレッドライブラリではスタックのサイズを変更することはできませんが、pthread_attr_setstacksize()を使って調整したをpthread_create()に指定すると、C pthreadsライブラリでこれを行うことができます。 this stackoverflow questionも参照してください。

+0

システムに合計128 MBのRAMがある場合、プロセスのアドレス空間が不足する可能性は低いです。 LinuxはまずRAMを使い果たす可能性が高いです。 – MSalters

+0

@MSalters:Linuxはメモリをオーバーコミットしているため、RAMを使い果たす前にアドレス空間が不足する可能性があります。 –

+0

理論的には、約80MBのRAM(20Kページ)と2048MBのアドレス空間(512Kページ)を使用すると、大規模なオーバーコミットが必要になります。 – MSalters

0

上記のコメントのulimit -sで報告した値は、スレッドが空のメインでもスタックを割り当てていることを示しています。スレッドで実行される関数呼び出しでは、x86上にいると仮定してスタックに戻りアドレスを渡す必要があります。

@カークレックSBはこれで正しい方向に向かっています。使用しているアロケータは、プログラムのヒープサイズに影響する可能性があります。 brkまたはsbrkへの呼び出しを繰り返さないようにするために、アロケータは通常より大きな初期ブロックメモリを要求します。アロケータが最初に初期化されたときに、4,8,32,64などの典型的なページ境界に沿ってきれいに整列する値は、MBの順番で値を期待することは不合理ではありません。

割り当てられるメモリの量を制御するには、結果が異なる場合があります。アロケータがmallopt機能をサポートしているかどうかを確認してください。少しの試行錯誤で、全体的なメモリ占有量を減らすことができます。そうでなければ、あなた自身のアロケータをいつでも実装することができます。

関連する問題