前言
最近在優化一個項目,發現使用asp.net api時候發現記憶體占用過高。從中發現有某處地方直接使用Newtonsoft.json 的JArray對象序列化後傳回HttpResponseMessage,
也有一部分是直接傳回JArray,後來懷疑JObject記憶體占用過高,此函數是使用隊列來生成報表檔案資料量比較大,而傳輸方式使用Json,解析為了友善而直接使用JArray.Parse,
改為反序列化IList<IDictionary<string,object>>後有所改觀;經筆者測試發覺JObject産生的對象确實對記憶體占用過多而無法準确釋放。
測試
Release測試1W條資料每行30列
一、NewtonsoftTest
string guid = Guid.NewGuid().ToString();
JArray array = new JArray();
for (int i=0; i < 10000; i++) {
JObject obj = new JObject();
for (int c=1; c <= 10; c++) {
obj["Id_" + c] = i;
obj["Guid_" + c] = guid;
obj["Sex_" + c] = i % 2 == 0;
}
array.Add(obj);
}
程序記憶體占用80M左右
二、FCLCollectionTest
string guid = Guid.NewGuid().ToString();
IList<IDictionary<string,object>> array = new List<IDictionary<string, object>>();
for (int i=0; i < 10000; i++) {
var obj = new Dictionary<string, object>();
for (int c=1; c <= 10; c++) {
obj["Id_" + c] = i;
obj["Guid_" + c] = guid;
obj["Sex_" + c] = i % 2 == 0;
}
array.Add(obj);
}
程序記憶體占用28M左右
三、JsonWriterTest
string guid = Guid.NewGuid().ToString();
var jsonWriter = new JsonTextWriter(new StringWriter(CultureInfo.InvariantCulture));
jsonWriter.Formatting = Formatting.None;
jsonWriter.WriteStartArray();
for (int i=0; i < 10000; i++) {
jsonWriter.WriteStartObject();
for (int c=1; c <= 10; c++) {
jsonWriter.WritePropertyName("Id_" + c);
jsonWriter.WriteValue(i);
jsonWriter.WritePropertyName("Guid_" + c);
jsonWriter.WriteValue(guid);
jsonWriter.WritePropertyName("Sex_" + c);
jsonWriter.WriteValue(i % 2 == 0);
}
jsonWriter.WriteEndObject();
}
jsonWriter.WriteEndArray();
程序記憶體占用24M左右
分析
因筆者時間不多,隻做了部分測試,使用CLRProfiler來分析程式的記憶體配置設定
1.使用Dictionary<string,object>來作為JObject的替代測試
2.使用Newtonsoft.json JObject測試
可以從圖中看到JProperty JValue JToken占用記憶體情況,而String,int,boolean屬于測試資料的記憶體配置設定
3.使用JsonTextWriter測試如下
以上測試隻截取部分圖例,更深層次讀者可以下載下傳源代碼自行調試觀看。
下載下傳源代碼
結語
JsonTextWriter和拼寫字元串差別不大,如果隻是把json以字元串形式傳回,盡量使用JsonTextWriter來處理,進而減少對象的生成。
JObject可以使用字典或者實體模型方式來代替,然後使用JsonConvert.SerializeObject 序列化。
轉載于:https://www.cnblogs.com/johnwu/archive/2013/02/19/2917286.html