String引起的OutOfMemory異常 + 如何計算C#對象所占內存的大小


問題:

在一個高並發的接口經常會報錯OutOfMemory,檢查了代碼和服務器各種配置之后感覺一切都正常……

百思不得其解,只能把報錯的一段拿出來測試,

最后發現是黃色這段代碼出了問題:

 1         public void TestOutOfMemory()
 2         {
 3             var result = string.Empty;  4             string BSID = "MH_SYS";
 5             string FType = "USR";
 6             DirectoryInfo outFolder = new DirectoryInfo(ConfigurationManager.AppSettings["filePath"]);
 7             var temp = outFolder.GetDirectories().Where(x => !x.Name.Contains("bak"));
 8             if (temp.Count() > 0)
 9             {
10                 try
11                 {
12  GC.Collect(); 13  GC.WaitForFullGCComplete(); 14                     long start = GC.GetTotalMemory(true); 15 
16                     var timeSpan = temp.OrderByDescending(x => x.Name).FirstOrDefault().Name;//獲取timeSpan文件夾名稱
17                     DirectoryInfo inFolder = new DirectoryInfo(ConfigurationManager.AppSettings["filePath"] + timeSpan + @"\" + BSID + @"\" + FType + @"\");
18                     if (inFolder.GetFiles().Count() > 0)
19                     {
20                         var list = inFolder.GetFiles().OrderBy(x => Convert.ToInt16(x.Name.Split('.')[0]));
21                         foreach (var item in list)
22                         {
23                             using (FileStream fs = new FileStream(item.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
24                             {
25                                 int fsLen = (int)fs.Length;
26                                 byte[] heByte = new byte[fsLen];
27                                 int r = fs.Read(heByte, 0, heByte.Length);
28                                 result += System.Text.Encoding.UTF8.GetString(heByte); 29                             }
30                         }
31                     }
32 
33  GC.Collect(); 34  GC.WaitForFullGCComplete(); 35                     long end = GC.GetTotalMemory(true); 36                     long size = end - start; 37 
38                     Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "\n" + (size/1024/1024) + "M\n" + result.GetHashCode() + "\n" + result.Substring(0,1000) + "\n\n\n\n");
39                 }
40                 catch (Exception e)
41                 {
42                     throw e;
43                 }
44             }
45         }

用日志記錄了下result這個String字符串的哈希編碼,發現在多個並發的情況下,都是一樣的,說明GC並沒有及時回收這個String。

也就是說接口並發時用的都是同一個String對象,加上接口所需要返回的內容很大,每個大概有30M左右,測試當5個並發的時候,占用內存就到了600-700M,10個並發的時候內存占用到了1.5G左右,所以OutOfMemory也不奇怪啦。

PS:計算C#對象所占內存的大小

 請參考上面代碼中灰色部分~~

 

解決方案:

找到問題根源之后很簡單,只要用StringBuilder代替String,用下面代碼替換上文黃色部分即可

StringBuilder result = new StringBuilder();

result.Append(System.Text.Encoding.UTF8.GetString(heByte));

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM