2011-02-07 312 views
2

我不確定主題是否正確,但我會嘗試在下面解釋我的問題。我正在尋找的是某種「學術答案」,因爲我想我的兩個解決方案在運行時都會給出類似的結果。網絡I/O和C++的緩衝區的動態與靜態內存分配

我在Linux上有一個C++程序,它執行大量的網絡I/O操作,我想知道是否更好地將內置緩衝區放入客戶端類或動態分配它。第一個解決方案使用內置的緩存:

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); 
} 

現在,比較兩個方案我看到的第一需要較少的內存分配操作,那麼第二個,接下來的事情 - 感謝模板編譯器在編譯時知道類的大小。第一個解決方案應該提供更好的參考局部性(?),並且編譯器也可以將類的大小與其想要的任何對齊。我們也可以直接訪問緩衝區,因爲我們不需要執行額外的指針取消引用操作。

我開始思考第一個解決方案中的TcpClient對象如何在處理器緩存中運行。每次我們在代碼中訪問這樣的對象時,它都會被加載到處理器緩存中,並且它的緩衝區也會被複制,即使我們不需要它們。它會使緩存效率低下,因爲我們在那裏存儲了大量數據,增加了內存查找錯誤的概率,對嗎?

是不是浪費處理器的時間來複制緩衝區來緩存所有的時間? 從處理器和操作系統的角度來看,這兩種解決方案的其他效果是什麼? 將班級規模縮小或儘可能多地增加班級規模會更好嗎?

+0

您可以在堆棧中分配緩衝區,並使用成員加入班級。順便說一句,你編寫C++,使用新的,而不是malloc! – neuro 2011-02-07 12:57:43

回答

4

處理器不會根據它在哪裏以不同的方式查找內存。在堆棧上分配速度要快得多,而且容易出錯。如果分配需要爲動態,則只使用動態分配,即需要變量生存期或對象類型。否則,使用靜態分配。

3

我不會在這裏關心緩存效果。無論如何,Socket I/O速度很慢且緩存效率低下,因爲它需要將系統調用和數據從內核緩衝區複製到用戶空間,所以沒有POSIX方法來執行零拷貝套接字I/O(可以使用自定義硬件來完成此操作)。你可以做的最好的事情是儘量減少通過套接字發送和接收數據所需的系統調用次數。

理想情況下,用戶空間接收緩衝區的大小應該與內核中套接字接收緩衝區的大小相同。這樣您就可以在一個recv/recvmsg/read()系統調用中讀取所有接收到的數據。

如果您沒有多次創建客戶端,構建對象需要多少分配可能並不重要。識別和優化I/O的快速路徑通常會更好,因此一旦構建客戶端對象,發送和接收數據就不涉及用戶空間中的內存分配和數據副本。