zoukankan      html  css  js  c++  java
  • 【实时】DevExpress内存监视

    前言

      在做项目的时候,我们有时候需要检测项目的内存占用情况,有时候是检测内存泄露~,有时候是查看某段代码执行前后的内存对比,以方便找出问题并以解决。

    内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。-百度百科

      前几天做项目的时候就遇到这种情况,项目是winform开发,大数据压缩、解压和绑定的时候,内存飙升的很快。虽然通过Windows任务管理器可以查看到进程的内存使用情况,但只是数值的体现,想要的效果:

      这种波线图可以直观的体现出程序的CPU使用情况,找了一下关于内存的,虽然在资源监视器中有内存的使用情况,但是并不是我想要的,也在网上找了下内存监视程序,找了大半天也没找到。

      自己动手,丰衣足食。

    DevExpress安装问题

      这里在多说句,其实用DevExpress也是没办法,网上找了好多图形控件,但都不是我想要的,虽然DevExpress比较大,但是大有大的好处,那就是功能很强大。

      关于DevExpress的安装写了一篇文章《DevExpress控件安装、汉化使用教程》,大家可以参考下。

      在安装完之后记得要安装DevExpress.Patch.13.1.5.exe这个补丁包,不然开发的程序每次都会弹出:

      还有一点就是安装完卸载的时候,一定要正确的卸载,有次我正在卸载的时候强制关机了,重新开机安装的时候,就会出现这种情况:

      虽然程序已经卸载,但还是提示模块已经安装,程序已经被破坏了,然后我就用软媒 - Win7优化大师(我认为是比较好的清理工具),深度清理了下垃圾文件和注册表,但是发现还是不行,肯定注册表文件没有清理干净,有点想要重装系统的冲动,单仅仅是冲动,没有行动,毕竟重装完系统要那么多的软件要重新安装,没办法就手动清理注册表吧,搜寻“DevExpress”有关的注册表,那不是一般的多啊,还有些是GUID生成的:

      一条一条的删啊,也不知道删了多少条,但我记得肯定没删完,我就是试了下重装,发现可以了。

      做事要有耐心。

    实现

      以上废话说的有点多,关于DevExpress的教程真的很少(中文),因为DevExpress太庞大了,只能通过DevExpress提供的示例程序去学习,实现上面波形图在DevExpress中有个控件叫SwiftPlotDiagram,位置在DevExpress.XtraCharts.v13.1.dll,使用DevExpress实现图形程序必须包含在ChartControl控件下。

      我们先看下设计器:

      除去实现内存监控这个程序,我们只考虑波形图,要实现一般有几个基本元素:

    •  坐标(SeriesPoint)
    •  时间刻度(TimeInterval)
    •  走势线RegressionLine)

    RegressionLine翻译是回归线的意思,就是一个总的大致走势方向,我称作走势线,只是个叫法不同。

      上面元素中坐标最重要,明白了元素我们看下代码:

     1         private const int interval = 20;
     2         private double value = 10.0;
     3         RegressionLine Regression { get { return GetRegressionLine(Series); } }
     4         private int TimeInterval
     5         {
     6             get
     7             {
     8                 return Convert.ToInt32(nud_Interval.Value);
     9             }
    10         }
    11         private Series Series
    12         {
    13             get
    14             {
    15                 return chartControl.Series.Count > 0 ? chartControl.Series[0] : null;
    16             }
    17         }

      上面几个字段就不解释了,value是纵坐标的值,也就是内存值,Series英文翻译是串联的意思,这边表示的是坐标组成曲线的集合,因为这边我们就画了一个曲线图所以是Series[0]。

     1         //获取进程
     2         private void getProcess()
     3         {
     4             foreach (Process item in Process.GetProcesses())
     5             {
     6                 cb_Process.Items.Add(item.ProcessName);
     7             }
     8             cb_Process.SelectedIndex = 0;
     9         }
    10         //获取下一个坐标值
    11         private double CalculateNextValue(double value)
    12         {
    13             Process process = Process.GetProcessesByName(cb_Process.Text)[0];
    14             return process.PrivateMemorySize64/1024.0;
    15         }

      getProcess()方法是获取本地线程集合填充到下拉列表中,CalculateNextValue()方法是更新纵坐标的值,也就是内存值,这个方法在timer事件中调用。

      我们看下timer事件代码:

     1         //timer事件
     2         private void timer_Tick(object sender, EventArgs e)
     3         {
     4             if (Series == null )
     5             {
     6                 return;
     7             }
     8             var argument = DateTime.Now;
     9             //一个刻度需要画的坐标
    10             var pointsToUpdate = new SeriesPoint[interval];
    11             for (var i = 0; i < interval; i++)
    12             {
    13                 pointsToUpdate[i] = new SeriesPoint(argument, value);
    14                 argument = argument.AddMilliseconds(1);
    15                 UpdateValues();
    16             }
    17             //添加坐标
    18             AddPoints(Series, pointsToUpdate);
    19             var minDate = argument.AddSeconds(-TimeInterval);
    20             //重新设置X轴MinMaxValues
    21             var diagram = chartControl.Diagram as SwiftPlotDiagram;
    22             if (diagram != null && diagram.AxisX.DateTimeScaleOptions.MeasureUnit == DateTimeMeasureUnit.Millisecond)
    23             {
    24                 diagram.AxisX.Range.SetMinMaxValues(minDate, argument); 
    25             }
    26         }

      timer事件主要做个三个工作,一是根据设置好的interval获取每个刻度的内存值,然后添加到Points数组中,interval的值越大,画出的波线图越精细,下面就是把Points数组的坐标值加到Series中,最后把X轴的最大小值设置下,以实现动态的效果,需要注意的是:

    1         diagram.AxisX.Range.SetMinMaxValues(minDate, argument);

      这句代码的意思不是设置整个X轴的最大小值,而是这个刻度下的最大小值,大家可以把这段代码注释下看下效果就知道了,可以看出时间刻度是一样的,并没有清除叠加。

      关于X轴-时间轴,我们可以在设计其中可以设置:

    1          swiftPlotDiagram1.AxisX.DateTimeScaleOptions.GridAlignment = DevExpress.XtraCharts.DateTimeGridAlignment.Millisecond;
    2          swiftPlotDiagram1.AxisX.DateTimeScaleOptions.MeasureUnit = DevExpress.XtraCharts.DateTimeMeasureUnit.Millisecond;
    3          swiftPlotDiagram1.AxisX.Label.DateTimeOptions.Format = DevExpress.XtraCharts.DateTimeFormat.Custom;
    4          swiftPlotDiagram1.AxisX.Label.DateTimeOptions.FormatString = "mm:ss";
    5          series1.ArgumentScaleType = DevExpress.XtraCharts.ScaleType.DateTime;

      上面是设置X轴-时间刻度为毫秒,下面是设置显示的格式,最下面代码的意思是设置曲线画图刻度的格式是DateTime格式,也就是上面SeriesPoint的argument

      下面关于图标标注的设置就是图形上面的标注PrivateMemory,因为所有的图形控件都集成在ChartControl中,只要找到设置起来很方便:

     1         this.chartControl.Legend.AlignmentHorizontal = DevExpress.XtraCharts.LegendAlignmentHorizontal.Left;
     2         this.chartControl.Legend.AlignmentVertical = DevExpress.XtraCharts.LegendAlignmentVertical.TopOutside;
     3         this.chartControl.Legend.Direction = DevExpress.XtraCharts.LegendDirection.LeftToRight;
     4         this.chartControl.Legend.Visible = true;
     5         series1.Name = "PrivateMemory";
     6         regressionLine1.Name = "Regression Line";
     7         swiftPlotSeriesView1.Indicators.AddRange(new DevExpress.XtraCharts.Indicator[] {
     8         regressionLine1});
     9         series1.View = swiftPlotSeriesView1;
    10         this.chartControl.SeriesSerializable = new DevExpress.XtraCharts.Series[] {
    11      series1};

      上面设置标注显示格式,设置名称只要设置series的name属性就行,不需要重新绑定,因为Legend是集成到chartControl中的,设置好后把series添加到chartControl中就可以显示了,如果要显示多个线性,只要再添加series即可。

      关于刻度标示的设置:

    1          swiftPlotDiagram1.AxisX.Title.Text = "时间";
    2          swiftPlotDiagram1.AxisX.Title.Visible = true;            
    3          swiftPlotDiagram1.AxisY.Title.Text = "内存大小(KB)";
    4          swiftPlotDiagram1.AxisY.Title.Visible = true;

      最后关于走势线RegressionLine,因为是集成在chartControl,用的时候只要指示需要体现的series,添加到Indicators集合中就可以了,看下代码:

     1         regressionLine1.Name = "Regression Line";
     2         swiftPlotSeriesView1.Indicators.AddRange(new DevExpress.XtraCharts.Indicator[] {
     3         regressionLine1});
     4 
     5         //获取走势线
     6         private static RegressionLine GetRegressionLine(Series series)
     7         {
     8             if (series != null)
     9             {
    10                 var swiftPlotView = series.View as SwiftPlotSeriesView;
    11                 if (swiftPlotView != null)
    12                 {
    13                     foreach (Indicator indicator in swiftPlotView.Indicators)
    14                     {
    15                         var regressionLine = indicator as RegressionLine;
    16                         if (regressionLine != null)
    17                         {
    18                             return regressionLine;
    19                         }
    20                     }
    21                 }
    22             }
    23             return null;
    24         }

      说了那么多,我们看下最后实现的效果(20毫秒,录制的比较卡):

      完整代码:

      1 using System;
      2 using DevExpress.DXperience.Demos;
      3 using DevExpress.XtraCharts;
      4 using System.Diagnostics;
      5 
      6 namespace MemoryMonitor
      7 {
      8     public partial class ChartDemoRealtimeChart : TutorialControlBase
      9     {
     10         private const int interval = 20;
     11         private double value = 10.0;
     12         RegressionLine Regression { get { return GetRegressionLine(Series); } }
     13         private int TimeInterval
     14         {
     15             get
     16             {
     17                 return Convert.ToInt32(nud_Interval.Value);
     18             }
     19         }
     20         private Series Series
     21         {
     22             get
     23             {
     24                 return chartControl.Series.Count > 0 ? chartControl.Series[0] : null;
     25             }
     26         }
     27         #region 界面事件
     28         //实例化事件
     29         public ChartDemoRealtimeChart()
     30         {
     31             InitializeComponent();
     32             Regression.Visible = false;
     33             getProcess();
     34         }
     35         //timer事件
     36         private void timer_Tick(object sender, EventArgs e)
     37         {
     38             if (Series == null )
     39             {
     40                 return;
     41             }
     42             var argument = DateTime.Now;
     43             //一个刻度需要画的坐标
     44             var pointsToUpdate = new SeriesPoint[interval];
     45             for (var i = 0; i < interval; i++)
     46             {
     47                 pointsToUpdate[i] = new SeriesPoint(argument, value);
     48                 argument = argument.AddMilliseconds(1);
     49                 UpdateValues();
     50             }
     51             //添加坐标
     52             AddPoints(Series, pointsToUpdate);
     53             var minDate = argument.AddSeconds(-TimeInterval);
     54             //重新设置X轴MinMaxValues
     55             var diagram = chartControl.Diagram as SwiftPlotDiagram;
     56             if (diagram != null && diagram.AxisX.DateTimeScaleOptions.MeasureUnit == DateTimeMeasureUnit.Millisecond)
     57             {
     58                 diagram.AxisX.Range.SetMinMaxValues(minDate, argument); 
     59             }
     60         }
     61         //开始/暂停
     62         private void btnStart_Click(object sender, EventArgs e)
     63         {
     64             timer.Enabled = !timer.Enabled;
     65             btnStart.Text = timer.Enabled ? "暂停" : "开始";
     66         }
     67         //显示走势线
     68         private void cb_RegressionLine_CheckedChanged(object sender, EventArgs e)
     69         {
     70             if (Regression != null)
     71                 Regression.Visible = cb_RegressionLine.Checked;
     72         }
     73         //选择需要监控的进程
     74         private void cb_Process_SelectedIndexChanged(object sender, EventArgs e)
     75         {
     76             Series.Points.Clear();
     77         }
     78         #endregion
     79         #region Some方法
     80         //获取下一个坐标值
     81         private double CalculateNextValue(double value)
     82         {
     83             Process process = Process.GetProcessesByName(cb_Process.Text)[0];
     84             return process.PrivateMemorySize64/1024.0;
     85         }
     86         //更新坐标值值
     87         private void UpdateValues()
     88         {
     89             value = CalculateNextValue(value);
     90         }
     91         //添加坐标
     92         private void AddPoints(Series series, SeriesPoint[] pointsToUpdate)
     93         {
     94             if (series.View is SwiftPlotSeriesViewBase)
     95             {
     96                 series.Points.AddRange(pointsToUpdate);
     97             }
     98         }
     99         //获取走势线
    100         private static RegressionLine GetRegressionLine(Series series)
    101         {
    102             if (series != null)
    103             {
    104                 var swiftPlotView = series.View as SwiftPlotSeriesView;
    105                 if (swiftPlotView != null)
    106                 {
    107                     foreach (Indicator indicator in swiftPlotView.Indicators)
    108                     {
    109                         var regressionLine = indicator as RegressionLine;
    110                         if (regressionLine != null)
    111                         {
    112                             return regressionLine;
    113                         }
    114                     }
    115                 }
    116             }
    117             return null;
    118         }
    119         //获取进程
    120         private void getProcess()
    121         {
    122             foreach (Process item in Process.GetProcesses())
    123             {
    124                 cb_Process.Items.Add(item.ProcessName);
    125             }
    126             cb_Process.SelectedIndex = 0;
    127         }
    128         #endregion
    129     }
    130 }
    View Code

      示例程序下载:MemoryMonitor.rar

    后记

      swiftPlotDiagram只是chartControl的冰山一角,chartControl只是DevExpress的冰山一角,DevExpress只是扩展控件的冰山一角,扩展控件只是。。。

      学无止境,不得不学。

  • 相关阅读:
    linux 终端光标消失问题
    linux系统中条件测试语句
    linux shell if语句
    linux shell for循环
    linux 系统中read命令
    linux中while循环语句
    linux shell脚本中流程控制语句 if 、for、while、case
    pc端WINCE的安装包
    WinCE程序的几种开发方法
    Wince 下开发技巧(一)查看内存
  • 原文地址:https://www.cnblogs.com/xishuai/p/3558979.html
Copyright © 2011-2022 走看看