实时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翻译是回归线的意思,就是一个总的大致走势方向,我称作走势线,只是个叫法不同。

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

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

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

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

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

  我们看下timer事件代码:

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

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

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

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

\

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

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

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

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

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

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

  关于刻度标示的设置:

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

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

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

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

\

  完整代码:


加载中...
001. 1 using System;
002. 2 using DevExpress.DXperience.Demos;
003. 3 using DevExpress.XtraCharts;
004. 4 using System.Diagnostics;
005. 5
006. 6 namespace MemoryMonitor
007. 7 {
008. 8     public partial class ChartDemoRealtimeChart : TutorialControlBase
009. 9     {
010. 10         private const int interval = 20;
011. 11         private double value = 10.0;
012. 12         RegressionLine Regression { get { return GetRegressionLine(Series); } }
013. 13         private int TimeInterval
014. 14         {
015. 15             get
016. 16             {
017. 17                 return Convert.ToInt32(nud_Interval.Value);
018. 18             }
019. 19         }
020. 20         private Series Series
021. 21         {
022. 22             get
023. 23             {
024. 24                 return chartControl.Series.Count > 0 ? chartControl.Series[0] : null;
025. 25             }
026. 26         }
027. 27         #region 界面事件
028. 28         //实例化事件
029. 29         public ChartDemoRealtimeChart()
030. 30         {
031. 31             InitializeComponent();
032. 32             Regression.Visible = false;
033. 33             getProcess();
034. 34         }
035. 35         //timer事件
036. 36         private void timer_Tick(object sender, EventArgs e)
037. 37         {
038. 38             if (Series == null )
039. 39             {
040. 40                 return;
041. 41             }
042. 42             var argument = DateTime.Now;
043. 43             //一个刻度需要画的坐标
044. 44             var pointsToUpdate = new SeriesPoint[interval];
045. 45             for (var i = 0; i < interval; i++)
046. 46             {
047. 47                 pointsToUpdate[i] = new SeriesPoint(argument, value);
048. 48                 argument = argument.AddMilliseconds(1);
049. 49                 UpdateValues();
050. 50             }
051. 51             //添加坐标
052. 52             AddPoints(Series, pointsToUpdate);
053. 53             var minDate = argument.AddSeconds(-TimeInterval);
054. 54             //重新设置X轴MinMaxValues
055. 55             var diagram = chartControl.Diagram as SwiftPlotDiagram;
056. 56             if (diagram != null && diagram.AxisX.DateTimeScaleOptions.MeasureUnit == DateTimeMeasureUnit.Millisecond)
057. 57             {
058. 58                 diagram.AxisX.Range.SetMinMaxValues(minDate, argument);
059. 59             }
060. 60         }
061. 61         //开始/暂停
062. 62         private void btnStart_Click(object sender, EventArgs e)
063. 63         {
064. 64             timer.Enabled = !timer.Enabled;
065. 65             btnStart.Text = timer.Enabled ? '暂停' '开始';
066. 66         }
067. 67         //显示走势线
068. 68         private void cb_RegressionLine_CheckedChanged(object sender, EventArgs e)
069. 69         {
070. 70             if (Regression != null)
071. 71                 Regression.Visible = cb_RegressionLine.Checked;
072. 72         }
073. 73         //选择需要监控的进程
074. 74         private void cb_Process_SelectedIndexChanged(object sender, EventArgs e)
075. 75         {
076. 76             Series.Points.Clear();
077. 77         }
078. 78         #endregion
079. 79         #region Some方法
080. 80         //获取下一个坐标值
081. 81         private double CalculateNextValue(double value)
082. 82         {
083. 83             Process process = Process.GetProcessesByName(cb_Process.Text)[0];
084. 84             return process.PrivateMemorySize64/1024.0;
085. 85         }
086. 86         //更新坐标值值
087. 87         private void UpdateValues()
088. 88         {
089. 89             value = CalculateNextValue(value);
090. 90         }
091. 91         //添加坐标
092. 92         private void AddPoints(Series series, SeriesPoint[] pointsToUpdate)
093. 93         {
094. 94             if (series.View is SwiftPlotSeriesViewBase)
095. 95             {
096. 96                 series.Points.AddRange(pointsToUpdate);
097. 97             }
098. 98         }
099. 99         //获取走势线
100. 100         private static RegressionLine GetRegressionLine(Series series)
101. 101         {
102. 102             if (series != null)
103. 103             {
104. 104                 var swiftPlotView = series.View as SwiftPlotSeriesView;
105. 105                 if (swiftPlotView != null)
106. 106                 {
107. 107                     foreach (Indicator indicator in swiftPlotView.Indicators)
108. 108                     {
109. 109                         var regressionLine = indicator as RegressionLine;
110. 110                         if (regressionLine != null)
111. 111                         {
112. 112                             return regressionLine;
113. 113                         }
114. 114                     }
115. 115                 }
116. 116             }
117. 117             return null;
118. 118         }
119. 119         //获取进程
120. 120         private void getProcess()
121. 121         {
122. 122             foreach (Process item in Process.GetProcesses())
123. 123             {
124. 124                 cb_Process.Items.Add(item.ProcessName);
125. 125             }
126. 126             cb_Process.SelectedIndex = 0;
127. 127         }
128. 128         #endregion
129. 129     }
130. 130 }

后记

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值