2011-08-01 7 views
1
私は、次のタイプ

メモリ使用量 - 予想通りメモリ使用量を減少させなかったdoubleからfloatへの変換

template<class T> 
struct node 
{ 
    //some functions 
private: 
    T m_data_1; 
    T m_data_2; 
    T m_data_3; 

    node* m_parent_1; 
    node* m_parent_2; 
    node* m_child; 
} 

テンプレートの目的は、ユーザーを有効にするためにあるのですクラスの何百万を初期化しています

floatまたはdoubleの精度を選択すると、node<float>のメモリ容量が少なくなります。

しかし、doubleからfloatに切り替えると、私のプログラムのメモリフットプリントは期待通りに減少しません。私は2つの質問、

  1. はそれが可能コンパイラ/オペレーティング・システムは私の山車のために必要以上のスペースを確保する(あるいはdoubleとしてそれらを格納)されていることであるがあります。もしそうなら、どうやってこれを止めるのですか?64ビットマシンでlinuxをg ++で使っています。

  2. すべての異なるクラスで使用されているメモリ量を判断できるツールはありますか? (すなわち、何らかの種類のメモリプロファイリング) - 私が考えていない他の場所でメモリが詰まっていないことを確認する。

+0

sizeofノードを使用してください。つまり、sizeofノード、sizeofノードです。 – QuentinUK

答えて

5

64ビット用にコンパイルされている場合、各ポインタは、サイズが64ビットであろう。これはまた、64ビットに整列させる必要があるかもしれないことを意味します。したがって、3つのフロートを格納する場合、4バイトのパディングを挿入する必要があります。したがって、12バイトを節約する代わりに、8を保存するだけです。ポインターが構造体の先頭か終わりにあるかどうかにかかわらず、パディングはそこに残ります。これは配列内の連続した構造体を整列を維持し続けるために必要です。

また、構造体は主に3つのポインタで構成されています。保存する8バイトは、48バイトのオブジェクトから40バイトのオブジェクトに移動します。それはまさに大きな減少ではありません。 64ビット用にコンパイルしている場合も同じです。

32ビット用にコンパイルしている場合は、36バイト構造から12バイトを保存します。これはパーセンテージに従って優れています。ダブルスを8バイトに整列させる必要がある場合は、潜在的に多くの。

新しい/ malloc関数を呼び出すと、それは必ずしもメモリを割り当てる呼び出しOSと1対1に対応していない:ニコルが作る有効なポイントにaddtionで

+0

この場合、ノードポインタのデータの間にパディングが追加されますが、フィールドの順序を変更するとパディングが計算されるので、ノード n [2]は2番目のエントリを持つように計算されますaligned - 最初にノードを置くと、データは構造体の最後にパディングを結果として生み出します。 –

1

。これは、高価なシステムコールの数を減らすために、ヒープマネージャーは新しい/ mallocを呼び出すときに、要求された以上のものを割り当ててから、それを「サブアロケート」することができるからです。また、メモリは一度に4kbしか割り当てられません(通常、これが最小ページサイズです)。基本的には、今後の割り当てを高速化するために、現在積極的に使用されていないメモリチャンクが割り当てられている可能性があります。

直接あなたの質問に答えるために:

1)はい、ランタイムは非常に可能性がより多くのメモリを割り当てます、あなたはを求めた - しかし、このメモリが無駄にされていない、それは今後のニュース/ mallocをのために使用されるであろうが、まだ "タスクマネージャ"またはあなたが使用するツールで表示されます。いいえ、フロートを倍に昇格させません。より多くの割り当てを行うほど、このエッジ条件がサイズの違いの原因になる可能性は低くなり、Nicolのアイテムが支配的になります。割当数が少ない場合、この項目は支配的になりがちです(「大」と「小」はOSとカーネルに完全に依存します)。

2)Windowsのタスクマネージャは、割り当てられた合計メモリを提供します。WinDbgのようなものは、実際には実行時に割り当てられた仮想メモリ範囲のチャンク(通常ツリーに割り当てられている)を与えます。 Linuxの場合、このデータはプロセスに関連付けられた/ procディレクトリにあるファイルの1つで利用可能になると思います。

3

他の回答は矛盾の原因については正しいです。しかし、x86/x86-64上のポインタ(および他のタイプ)は、であり、は整列する必要はありません。 GCCがパフォーマンスを向上させるのは、GCCがデフォルトで整列している理由です。

しかし、GCCは、あなたがこの上のコントロールを発揮させるために "パック" の属性が用意されています

私のシステムで
#include <iostream> 

template<class T> 
struct node 
{ 
private: 
    T m_data_1; 
    T m_data_2; 
    T m_data_3; 

    node* m_parent_1; 
    node* m_parent_2; 
    node* m_child; 
} ; 

template<class T> 
struct node2 
{ 
private: 
    T m_data_1; 
    T m_data_2; 
    T m_data_3; 

    node2* m_parent_1; 
    node2* m_parent_2; 
    node2* m_child; 
} __attribute__((packed)); 

int 
main(int argc, char *argv[]) 
{ 
    std::cout << "sizeof(node<double>) == " << sizeof(node<double>) << std::endl; 
    std::cout << "sizeof(node<float>) == " << sizeof(node<float>) << std::endl; 
    std::cout << "sizeof(node2<float>) == " << sizeof(node2<float>) << std::endl; 
    return 0; 
} 

(x86-64で、G ++ 4.5.2)、このプログラムの出力:

sizeof(node<double>) == 48 
sizeof(node<float>) == 40 
sizeof(node2<float>) == 36 

もちろん、「属性」メカニズムと「パック」属性自体はGCC固有のものです。