zoukankan      html  css  js  c++  java
  • 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无法调试)

  • 相关阅读:
    ADO.NET Entity Framework之ObjectQuery
    高效byte[]和string互转的方法
    异步邮件发送
    ADO.NET Entity Framework之ObjectContext
    【转】Memcache and Mongodb
    一周工作总结一次SQL优化记录
    Ubuntu下有关Java和数据库的一些工作记录(一)
    自定义函数,替换字符串中指定位置的字符
    一次优化记录
    对比shrink和move
  • 原文地址:https://www.cnblogs.com/miketwais/p/wpf_OutOfMemoryException.html
Copyright © 2011-2022 走看看