2011-02-07 32 views
2

トピックが正しいかどうかはわかりませんが、私は下の問題を説明しようとします。私が探しているのは、ある種の「学問的な答え」です。なぜなら、両方のソリューションが実行時に同様の結果をもたらすと考えているからです。ネットワークI/OとC++用のバッファの動的なメモリ割り当てと静的なメモリの割り当て

私は、Linux上で多くのネットワークI/O操作を実行するC++プログラムを持っています。クライアントのクラスに組み込みのバッファを置いたり、動的に割り当てるのがよいかどうか疑問です。最初のソリューション使用して内蔵のバッファ:

template <size_t buffer_size> class Buffer 
{ 
    // ... 

    char buffer [buffer_size]; 
} 

class TcpClient 
{ 
    // ... 

    Buffer<1024> input_buffer; 
    Buffer<1024> output_buffer; 
} 

第二に使用して動的に割り当てられたバッファ:今

class Buffer 
{ 
    Buffer (size_t buffer_size) : 
     buffer (malloc (buffer_size)) 
    { 
     // ... 
    } 

    // ... 

    char* buffer; 
} 

class TcpClient 
{ 
    // ... 

    Buffer input_buffer (1024); 
    Buffer output_buffer (1024); 
} 

は、私が見るの両方のソリューションを比較すると、最初は、第2の1、次のことを少ないメモリ割り当て操作が必要であること - 感謝をテンプレートコンパイラはコンパイル時にクラスサイズを知っています。最初の解決策はより良い参照地域(?)を与えるべきであり、コンパイラはクラスのサイズを望みどおりに合わせることもできます。また、バッファへの直接アクセスもあります。これは、追加のポインタ逆参照操作を実行する必要がないためです。

最初の解決策のTcpClientオブジェクトがどのようにプロセッサキャッシュ内で動作するのか考え始めました。そのようなオブジェクトをコード内でアクセスするたびに、プロセッサのキャッシュにロードされ、必要でなくてもバッファがコピーされます。それは、私たちがたくさんのデータを格納するので、メモリ検索の失敗確率を増やすために、キャッシュが非効率的になる可能性があります。

いつもバッファをキャッシュにコピーするのはプロセッサの時間を浪費していませんか? プロセッサとオペレーティングシステムの観点から見た両方のソリューションの他の効果は何ですか? クラスサイズを小さくしたり、できるだけintを組み込んだほうがよいですか?

+0

クラスにメンバーを使用して、バッファをスタックに割り当てることができます。あなたがC++をコードする方法では、mallocではなくnewを使用してください! – neuro

+0

"コードでこのようなオブジェクトにアクセスするたびに、プロセッサのキャッシュにロードされ、バッファもコピーされます" - これはあまり真実ではありません。私が考えることができるアーキテクチャでは、メモリは、オブジェクトがどこにあるかにかかわらず、固定サイズのページ/行(どのキャッシュに依存するか)によってキャッシュされます。その行がロードされている行を使用します。'TcpClient'オブジェクトの配列を作成し、バッファを使用しない多くの操作を行う場合、外部バッファ*は、複数のオブジェクトを1行に収めることを意味し、処理速度を上げます少し。それ以外の場合は、そのアカウントに違いはありません。 –

答えて

4

プロセッサは、メモリがどこにあるかによって異なるメモリを検索しません。スタックに割り当てる方がはるかに高速で、エラーが発生しにくい。割り当てが動的である必要がある場合にのみ、ダイナミックアロケーションを使用します。つまり、オブジェクトの可変ライフタイムまたはタイプが必要です。それ以外の場合は、静的割り当てを使用します。

3

私はここでキャッシュ効果には関係しません。とにかくシステムコールやカーネルバッファからユーザスペースへのデータコピーが必要なため、ソケットI/Oは遅く、キャッシュは非効率です。ゼロコピーソケットI/Oを行うPOSIXの方法はありません(カスタムハードウェアで行うこともできます)。ソケットを介してデータを送受信するために必要なシステムコールの数を最小限に抑えることが最善の方法です。

ユーザスペース受信バッファのサイズは、理想的にはカーネル内のソケット受信バッファのサイズと同じにする必要があります。このようにして、受信したすべてのデータを1つのrecv/recvmsg/read()システムコールで読み取ることができます。

クライアントを1秒間に何度も作成しない場合、オブジェクトを構築するために必要な割り当ての数は問題にならない場合があります。 I/Oの高速パスを特定して最適化する方が良い場合があります。そのため、クライアントオブジェクトの構築が完了した後、データの送受信にはユーザー領域にメモリ割り当てやデータコピーが含まれません。