2014-02-09 23 views
3

我有一個concat兩字節[]的問題。其中一個擁有超過300,000,000字節。這是拋出System.OutOfMemoryException類型的例外。concat兩個字節[]返回System.OutOfMemoryException

我用這個代碼:

byte[] b3 = by2.Concat(by1).ToArray(); 

有人能幫助我

+0

你連接磁盤上的兩個文件?或者這些字節數組從哪裏填充? – Magnus

回答

7

由於Concat致電ToArray對結果數組的大小不得而知。它無法創建適當的大數組,並只填充數據。因此,只要有更多的數據要填寫,它就會創建一個小的,然後當它滿了時,會一次又一次地創建兩倍大小的新的。這樣你需要更多的內存,然後只需理論(b1.Length + b2.Length) * 2。而且事情變得更加棘手,因爲在某些點之後,這些大數組被分配在LOH上,並且不像GC那樣容易地將它們作爲普通對象收集起來。

這就是爲什麼你不應該在這種情況下使用ToArray()並以舊式的方式來做:分配新的數組,其大小等於源數組的大小並複製數據。

喜歡的東西:

var b3 = new byte[b1.Length + b2.Length]; 
Array.Copy(b1, b2, b1.Length); 
Array.Copy(b1, 0, b2, b1.Length, b2.Length); 

它不保證成功,但使得它更容易。並執行很多很多,然後更快,然後ToArray()

+0

只是一個小問題:問題不是「ToArray」。如果你看它的源代碼,你會發現它的行爲不同,如果源是「ICollection」(一個'byte []'也是'ICollection ')。問題在於'Concat'返回'ConcatIterator'對象,然後'ToArray'必須使用通用的'ToArray'方法和你描述的效果。 – Dirk

+0

@Dirk是的,你是對的。 'b1.ToArray()'可以很好的使用'b1.CopyTo'。我已經添加到我的答案。 – MarcinJuraszek

1

那麼,對於自身錯誤消息TAKS,你沒有的RAM可用連續〜550MB。也許它太分散了。

+0

Yeha。儘管.....應該在64位應用程序上工作,但它並不是真的需要內存日誌,只是一個連續的區域,而64位應該在那裏。 – TomTom

1

嗯..你知道,從系統請求一個〜600meg的連續塊 - 我並不感到驚訝。它本身就是一個非常大的塊,並且假設你還必須在內存中有源數組,那就是超過1GB的原始數據塊。

你應該開始考慮其他數據結構 或試圖保持他們作爲文件並將它們映射到內存 編輯:memmapping整個文件需要在地址空間中相同的連續區域,所以它不會解決任何問題。這個答案將被刪除。

+0

能否請你用示例代碼支持你的回答 – MaRiO

+0

不,對不起。它很大程度上取決於你以後實際想要對數據做什麼**。最有可能的是,你並不真的「想要連接兩個300meg的數據」,僅僅是爲了獲得它的樂趣。你想粘上它,因爲你想稍後對它們做些什麼。例如,你想寫一個巨集到一個文件。或者,你想要從它們中計算出一些值。或者,你想把它看作一部電影,而不是兩部電影。等等。每一種最終的使用**都可能引導你去傳遞數據的許多其他方式,這樣**可以避免必須將它合併成巨大的數組。 – quetzalcoatl

+0

例如,如果您想「將數據作爲整體傳遞給某個算法」,則可以嘗試使用IList 而不是byte []來實現IList接口,以便從兩個數組中讀取數據**好像**他們加入了。如果你想把它們寫入文件 - 只需寫入第一個數組,然後**將第二個數組追加到同一個文件中(實際上,只需打開文件,寫入第一個和寫入第二個)。等等。至於內存映射文件,它不會幫助你「粘貼數據」。它可以幫助您在存儲器中「保存大量數據」,而無需一次讀取所有數據。 – quetzalcoatl

2

當處理這些數據時,我認爲你應該使用流(這當然取決於應用程序)。

然後,您可以擁有處理數據的代碼,而不需要將所有數據同時加載到內存中,也可以創建專用的流類作爲兩個流之間的串聯。

+0

你可以請示例代碼支持你的答案 – MaRiO