2010-01-05 101 views
1

我有一個用C#編寫的TCP服務器,它處理髮送給它的POST數據。目前它工作正常,除非大量的數據(即大於1GB)被髮送到它然後它耗盡內存(我將它全部存儲在內存中作爲一個字節數組(中間的List DTO))。現在,對於大文件,我將流式傳輸到磁盤,然後傳遞文件名以便從磁盤進行流式傳輸。TCP服務器和MemoryStreams/ByteArrays

目前我所有的例程都是爲了預期字節數組而寫的,事後看來,這是有點短視的。如果我只是將bytearray轉換爲內存流,它會使內存使用量翻倍嗎?我認爲重寫我的代碼以在memorystream上工作將允許我在從磁盤讀取流時重新使用它。

對不起,愚蠢的問題,我不知道什麼時候c#獲取數據的副本或何時需要引用。

回答

1

如果您將byte[]轉換爲MemoryStream,那麼它將在最初(在構造函數中)複製數據,但只要您釋放byte[]它就可以進行垃圾回收。本質上不存在「加倍」(特別是如果您可以正確設置尺寸,並直接寫入Stream而不是byte[])。

我會完全說開關Stream(但在API只使用Stream - 沒有什麼具體MOER;你消耗的代碼並不需要知道哪些類型)。最重要的是,您可以選擇使用NetworkStream(直接從套接字讀取)或FileStream(如果要緩衝到磁盤)或MemoryStream(如果要緩衝進程中)。您還需要確保通過基於流的代碼讀取該數據量。迭代器塊(yield return)在這裏可以非常有幫助,LINQ Enumerable方法(除了OrderBy,GroupBy等,哪個緩衝區)。

既沒有通過byte[]也沒有通過Stream導致任何東西被複制,因爲它們是引用類型 - 複製的唯一東西是引用(4或8個字節,取決於x86/x64)。

0

MemoryStream只是一個字節數組的流封裝,所以你不會因爲使用它而獲得任何東西。

你需要做什麼(對於大文件至少)是打開一個FileStream並在其中轉儲數據。在較低的級別,您必須從連接中讀取X個字節,然後立即將其寫入文件流。這樣你就不會將內存中的內容全部轉換成內存,而只需要一次處理幾個字節。

這是否容易做取決於你的TCP服務器是如何編碼的。

0

由於字節是一個值類型,如果您將它傳遞給一個沒有ref關鍵字的函數,那麼每次都會處理一個副本。如果您使用ref關鍵字傳遞它,它將引用原始字節數組。

memorystream是一個引用類型,所以它不會複製數據,但是您傳遞的是對該數據的引用,所以在使用該引用時內存使用量不會增加一倍。

+0

OP詢問關於傳遞一個字節[],據我所知,所有數組都是引用類型。它可能會保存值類型(在這個例子中是字節),但是數組本身是一個引用類型。 – trickdev 2011-11-21 11:43:32