c#+wpf項目性能優化之OutOfMemoryException解密


近期,使用c#+wpf開發的軟件准備正式投入使用了,使用前進行了大量的測試,測試后發現了一些問題,其中最讓人頭疼的就是軟件的性能問題(穩定性)。

這里的穩定性具體表現在機器的cpu占有率和內存使用情況:

1,CPU占用率節節攀升。

2,可用內存越來越少,最后爆OutOfMemoryException。

這兩點足以影響軟件的應用,一日不除,終日不得安寧!

發現問題后,多方搜尋資料,最終問題解決,這里做一些記錄,一來分享給各路開發者,二來記錄以備自己查看。

導致cpu占用率高:

 

1.是否有textbox的不斷循環中取值,賦值以及ScrollToend,解決方法:將TextBox控件換成ListBox,這樣是一行一行插入

2.搜索代碼中是否有while死循環。解決方法:優化代碼,刪掉死循環,while循環中可以加入

   system.application.doevent();

   thread.sleep(100);

我本人的項目中就是因為存在大量對textBox的操作,而導致的,我將TextBox控件換成ListBox后CPU占用率明顯下降。

 

導致可用內存越來越少的原因:

1.界面上很多動畫切換效果,如:gif動畫的幀切換,解決方法gif動畫暫用大量內存,需要及時釋放,盡量少用gif

2.界面上顯示很多圖片,圖片資源未回收,解決方法:釋放圖片資源

     一:將Image類轉換成Bitmap類
    System.Drawing.Image img = System.Drawing.Image.FromFile(filepath);
    System.Drawing.Image bmp = new System.Drawing.Bitmap(img);
    img.Dispose();
    然后使用 bmp作為PictureBox的圖片源
    二:從流中讀取
    FileStream fileStream = new FileStream("文件名", FileMode.Open, FileAccess.Read);
    pictureBox1.Image = Image.FromStream(fileStream);
    fileStream.Close();
    fileStream.Dispose(); 

3.非托管資源及其內存回收,對可能多次調用的類,應該嚴格按照“清理模式”格式書寫,保證類資源被及時釋放:

    標准的清理模式(~dispose)寫法:

    

MyClass:IDisposable
    {
        private bool disposed = false;
        ~MyClass()
        {
            Dispose(false);
        }
    
        public void Dispose()
        {
           Dispose(true);
           GC.SuppressFinalize(this);
        }
       
       private void Dispose(bool disposing)
       {
          if(disposed == false)
          {
               if(disposing == true)
               {
                  // 釋托管代碼
                  ......
               }
              // 釋非代碼
             ......
          }
          disposed = true;
       }
   }
View Code

4.確保萬無一失,使用using(){}來引用類,使用方法:

    using(classA a =new classA()){
      //用完后就釋放
    }
    只有繼承:IDisposable的類才能用using

5.網上給出了一個強制回收內存的方法,貌似看起來內存占用是減少了,一調用內存就降下來。先別高興太早,這其實是偽釋放,只為暫時解決內存大量泄露導致系統崩潰而急需解決的情況。
具體原因:http://blog.sina.com.cn/s/blog_49f8960e0100081x.html,關鍵字:將物理內存轉到虛擬內存,涉及磁盤讀寫。

ps:為了好看一點,我們可以加進去!

  具體代碼:

[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
/// <summary>
/// 釋放內存
/// </summary>
public static void ClearMemory()
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    if (Environment.OSVersion.Platform == PlatformID.Win32NT)
    {
 SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
    }
}
View Code

6.最后的殺手鐧,查看軟件中是否調用過什么開源插件,升級插件到穩定版本。

  本人項目中就遇到這個問題,本人項目中使用了cefsharp插件,期初使用的是低版本,這次索性升級到最新版本,然后將.net框架也升級了(其中也遇到了一些問題,NuGet資源下載慢,.net升級后與原來的部分庫文件不匹配等,打怪升級各個擊破吧!),然后就奇跡的解決了問題,所以最后結論就是需要不斷的嘗試和改進,尋找一切可能的突破口來解決問題。

 

-------------------------------分隔線-----------------------

寫在最后:對於c#程序的性能優化工作,我們可以多實用工具,工欲善其事必先利其器,如:

1.vs自帶的性能分析工具:

分析->診斷,按照指導操作。

2.ANTS Performance Profiler和ANTS Memory Profiler,分別用來做性能分析和內存占用分析,講具體操作方法自行百度,能夠准確找到性能瓶頸所在。

3.DotTrace,和上面的工具類似。

4.可以安裝.net reflection來查看dll具體方法(可能會導致vs無法調試)


免責聲明!

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



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