簡體   English   中英

實體框架-OutOfMemory異常

[英]Entity Framework - OutOfMemory Exception

我正在開發Silverlight商業應用程序,並希望實現“多部分”上傳,它將單個文件拆分為4096KB的大小。 要將這些部分從客戶端上傳到服務器,我正在使用WebClient(客戶端)和通用處理程序(* .ashx,服務器端)。

策略:在第一部分中,創建了一個實體框架類的新實例。 該對象具有字段/屬性“ binary”(在SQL中為varbinary(MAX),在Entity Framework中為byte [])。 我將第一部分存儲在屬性“ binary”中並執行SaveChanges()。 然后,處理程序將此新對象的ID(主鍵)返回給客戶端。

對服務器的第二個請求,除了文件的第二部分之外,還包含在第一個請求之后返回的ID。 在服務器上,我從數據庫中加載先前創建的對象,然后追加第二部分。

myobject.binary = myobject.binary.Concat(bytes).ToArray<byte>();

is the previously created object, the part I want to append to the property. 是先前創建的對象,將要附加到屬性的部分

我重復這種“策略”,直到將整個文件上傳到服務器。 對於最大大小約為78MB的文件,此方法可以正常工作。 對於大小為〜83MB的文件,它偶爾會起作用。 at SaveChanges(). 大小約為140MB的文件將在SaveChanges()處因中止。

堆棧跟蹤

at System.Object.MemberwiseClone()
at System.Array.Clone()
at System.Data.Common.CommandTrees.DbConstantExpression..ctor(TypeUsage resultType, Object value)
at System.Data.Mapping.Update.Internal.UpdateCompiler.GenerateValueExpression(EdmProperty property, PropagatorResult value)
at System.Data.Mapping.Update.Internal.UpdateCompiler.BuildSetClauses(DbExpressionBinding target, PropagatorResult row, PropagatorResult originalRow, TableChangeProcessor processor, Boolean insertMode, Dictionary`2& outputIdentifiers, DbExpression& returning, Boolean& rowMustBeTouched)
at System.Data.Mapping.Update.Internal.UpdateCompiler.BuildUpdateCommand(PropagatorResult oldRow, PropagatorResult newRow, TableChangeProcessor processor)
at System.Data.Mapping.Update.Internal.TableChangeProcessor.CompileCommands(ChangeNode changeNode, UpdateCompiler compiler)
at System.Data.Mapping.Update.Internal.UpdateTranslator.<ProduceDynamicCommands>d__0.MoveNext()
at System.Linq.Enumerable.<ConcatIterator>d__71`1.MoveNext()
at System.Data.Mapping.Update.Internal.UpdateCommandOrderer..ctor(IEnumerable`1 commands, UpdateTranslator translator)
at System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands()
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at MyObjectContext.SaveChanges(SaveOptions options) in PathToMyEntityModel.cs:Line 83.
at System.Data.Objects.ObjectContext.SaveChanges()
at MultipartUpload.ProcessRequest(HttpContext context) in PathToGenericHandler.ashx.cs:Line 73.

有誰知道我的實現有什么問題嗎? 如果您需要更多信息或代碼段,請告訴我。

親切的問候,克里斯

想一想。 上傳(例如)130 MB后,執行此行需要多少內存:

myobject.binary = myobject.binary.Concat(bytes).ToArray<byte>();

顯然,先前的陣列在內存中,即130 MB。 而且新數組也必須以某種方式存儲在內存中,另外130 MB,對嗎?

實際上,情況更糟。 Concat()正在產生一個序列,而ToArray()不知道它將有多大。

所以.ToArray()作用是創建一個內部緩沖區,並開始使用.Concat()迭代器的輸出填充它。 顯然,它不知道緩沖區應該有多大,因此每隔一段時間,它將發現傳入的字節數超過了其緩沖區可以容納的字節數。 然后,它需要創建一個更大的緩沖區。 它要做的就是創建一個緩沖區,其大小是前一個緩沖區的兩倍,復制所有內容並開始使用新緩沖區。 但這意味着在某個時候,舊緩沖區和新緩沖區必須同時在內存中。

在某些時候,舊緩沖區將為128 MB,新緩沖區將為256 MB。 再加上130 MB的舊文件,大約是半GB。 現在,我們希望沒有兩個(或更多)用戶同時執行此操作。

我建議您使用其他機制。 例如,將上傳的塊存儲在磁盤上的臨時文件中。 當出現新的塊時,只需將其追加到文件中即可。 僅在上傳完成后,才對文件執行所有操作,例如將其存儲在數據庫中。

另外,請注意,.NET中數組的最大大小受31位索引限制。 因此,無論系統中有多少RAM,字節數組的最大大小均為2 GB。

最后:如果要處理這么大的內存塊,請確保您正在64位進程中運行,至少在.NET 4.5上運行,以便可以利用.NET 4.5中的大對象堆改進 但這並不是魔術,因為“內存不足”並不表示物理內存

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM