我正在研究一些企業應用程序,每天處理大量數據,並且要使用C#.NET 4編寫WINDOWS SERVICE應用程序。它也與SQL SERVER 2008 R2有連接,但由於某些原因它(隨機)拋出我在同步表這個錯誤存儲JSON序列數據:SqlClient返回奇怪的OOM異常? C#.NET 4
Exception of type 'System.OutOfMemoryException' was thrown.
at System.Data.SqlClient.TdsParser.ReadPlpUnicodeChars(Char[]& buff, Int32 offst, Int32 len, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.ReadSqlStringValue(SqlBuffer value, Byte type, Int32 length, Encoding encoding, Boolean isPlp, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.ReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, Int32 length, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.ReadColumnData()
at System.Data.SqlClient.SqlDataReader.ReadColumn(Int32 i, Boolean setTimeout)
at System.Data.SqlClient.SqlDataReader.GetValueInternal(Int32 i)
at System.Data.SqlClient.SqlDataReader.GetValues(Object[] values)
此表是相當普遍的表,以保持LOB數據:即失敗了36.231
CREATE TABLE [dbo].[SyncJobItem](
[id_job_item] [int] IDENTITY(1,1) NOT NULL,
[id_job] [int] NOT NULL,
[id_job_item_type] [int] NOT NULL,
[id_job_status] [int] NOT NULL,
[id_c] [int] NULL,
[id_s] [int] NULL,
[job_data] [nvarchar](max) NOT NULL,
[last_update] [datetime] NOT NULL,
CONSTRAINT [PK_SyncJobItem] PRIMARY KEY CLUSTERED)
LOB記錄。在job_data
列中有800個字符的數據,這是(如果我們說1個字符是2個字節,UTF-8)約70MB的數據不多。
請考慮改變作業數據存儲(如磁盤)或類似的東西不是我的選擇。我想解決這個錯誤,所以如果有人知道任何事情,請幫助!
此外,這個錯誤在相同的數據上隨機發生,系統運行的是vmWare-vCloud,也就是我認爲的一些大刀片系統。我們有大約6GB的RAM專用於我們的vm(服務最多使用大約1-2GB),服務編譯爲x64,系統爲x64 Windows 2008R2 Standard。我已經確定沒有單個對象的內存超過2GB,所以不是這樣,SqlClient內部也有錯誤,而我從未見過它的15年開發經驗,Google什麼都沒發現。此外,錯誤不在DB端,因爲DB擁有超過32GB的RAM,並且只使用20GB的峯值。對於我在這個系統中使用的不常用的細節,在每個作業步驟之後(數據上有多個步驟)是多線程和GC.Collect()。
編輯:
這裏是做這個問題全碼:
internal static void ExecuteReader(IConnectionProvider conn, IList destination, IObjectFiller objectBuilder, string cmdText, DbParameterCollection parameters, CommandType cmdType, int cmdTimeout)
{
IDbCommand cmd = CreateCommand(conn.DBMS, cmdText, parameters, cmdType, cmdTimeout);
cmd.Connection = conn.Connection;
bool connIsOpennedLocally = EnsureOpenConnection(conn);
try
{
AssignExistingPendingTransactionToCommand(conn, cmd);
using (IDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleResult))
{
objectBuilder.FillCollection(reader, destination);
PopulateOutputParameterValues(parameters, cmd);
}
}
finally
{
CloseConnectionIfLocal(conn, connIsOpennedLocally);
cmd.Dispose();
}
}
...
private void FillFromAlignedReader(ICollection<TEntity> collection, IDataReader openedDataReader, IDbTable table)
{
// Fastest scenario: data reader fields match entity field completely.
// It's safe to reuse same array because GetValues() always overwrites all members. Memory is allocated only once.
object[] values = new object[openedDataReader.FieldCount];
while (openedDataReader.Read())
{
openedDataReader.GetValues(values);
TEntity entity = CreateEntity(table, EntityState.Synchronized, values);
collection.Add(entity);
}
}
你能澄清你「crunches large amount of data」是什麼意思嗎>你是否從你建議的表格中讀取數據並對數據進行處理?或者你正在閱讀其他表並寫入這張表嗎?數據處理完畢後,你對數據做了什麼?在最終刷新之前它是否保留在內存中,或者是否在逐行的基礎上從內存寫入和刷新? – GarethD
我正在將數據從SQL Server加載到DataTable。這是什麼時候呢。這是簡單的選擇語句。我正在對數據進行一些計算之前和之後。基本上,它是這樣的: 1)裝載從NoSQL的分貝(Couchbase)數據 2)聚集數據與地圖,減少 3)序列化聚合結果對象到JSON對象 4)保存到DB該表 5 )轉到下一步,從SQL加載JSON(這裏它與OOM分開) –
當您說*我已確保單個對象在內存中沒有超過2GB *時,是否在步驟5中包含DataTable?你能用一個只向前移動的SqlDataReader來實現同樣的事情嗎,這樣你在內存中一次只能有一行?我認爲查看拋出錯誤的代碼塊以及堆棧跟蹤會很有用。 – GarethD