【实时】DevExpress内存监视

原文:【实时】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只是扩展控件的冰山一角,扩展控件只是。。。

  学无止境,不得不学。

时间: 2024-10-25 09:24:19

【实时】DevExpress内存监视的相关文章

java-把常用高频访问数据从数据库加载到内存,数据库的变化能够自动实时更新内存。求大侠给思路

问题描述 把常用高频访问数据从数据库加载到内存,数据库的变化能够自动实时更新内存.求大侠给思路 把常用高频访问数据从数据库加载到内存,数据库的变化能够自动实时更新内存. 解决方案 其实数据库内部本身已经有这样的缓存机制,操作系统也有.你再做其实经常会弄巧成拙. 你知道"高频"数据的淘汰算法是什么么?这一点估计你写不过主流的数据库,那别的都是白扯. 解决方案二: 大型数据库本身带有很好的缓存机制,不需要咱们进行任何干预 解决方案三: 数据库更新的时候,把数据送到内存刷新换一下.

Github 开源项目(一)websocketd (实战:实时监控服务器内存信息)

官方地址:https://github.com/joewalnes/websocketd websocketd是WebSocket守护进程,它负责处理WebSocket连接,启动您的程序来处理WebSockets,并在程序和Web浏览器之间传递消息.  一.安装:websocketd  wget https://github.com/joewalnes/websocketd/releases/download/v0.2.12/websocketd-0.2.12-linux_amd64.zip u

Linux系统基本的内存管理知识讲解

  内存是Linux内核所管理的最重要的资源之一.内存管理系统是操作系统中最为重要的部分,因为系统的物理内存总是少于系统所需要的内存数量.虚拟内存就是为了克服这个矛盾而采用的策略.系统的虚拟内存通过在各个进程之间共享内存而使系统看起来有多于实际内存的内存容量.Linux支持虚拟内存, 就是使用磁盘作为RAM的扩展,使可用内存相应地有效扩大.核心把当前不用的内存块存到硬盘,腾出内存给其他目的.当原来的内容又要使用时,再读回内存. 一.内存使用情况监测 (1)实时监控内存使用情况 在命令行使用"Fr

windows2000秘密武器之内存工具

4. 内存快照 这个工具可以将所有内存资源的消耗情况写进一个日志文件中, 供以后分析使用,有点类似"快照"的方式.日志文件使用的默认名字是Memsnap.log,当然在建立这个日志文件时,也可以用其它你认为合适的名字.在win98和CW2KP中,系统信息中都有一个和这个工具的作用类似的程序:Dr Watson,俗称"系统快照".Win98中的Dr Watson功能过于简单,到了CW2KP中,Dr Watson的功能大大加强,特别是对出错程序列出的信息很详细,如果使用得当,对付出错程序的

在AIX V5.3中使用MALLOCDEBUG隔离并解决内存泄漏-用于完成烦琐任务的有用工具

AIX Version 5.3 中附带的 malloc 子系统监视工具 MALLOCDEBUG,可以帮助您隔离内存泄漏. 内存泄漏是非常棘手的问题,并且处理起来需要很大的代价,所以使用好的工具以确定并了解出现泄漏的 原因是非常重要的.本文中提供的示例代码将向您展示处理内存泄漏的一种方法. 引言 在编写应用程序时进行动态内存分配是非常必要的.它可以在程序运行的过程中帮助分配所需的内存 ,而不是在进程启动的时候就进行分配.然而,有效地管理这些内存同样也是非常重要的.在大型的.复 杂的应用程序中,内存

如何合理管理win7电脑的内存

  不知道大家在操作win7电脑的时候,会不会出现这样的情况,严重的内存分布不合理,有的磁盘占用了很多的空间,但是有的磁盘却十分的空旷,其实这就是一种磁盘空间运用不合理的状况,反之,如果咱们可以将磁盘空间更合理的布局使用,更合理的管理,那么就更能体现ghost win7的强大性.下面,咱们就来说说如何合理的管理win7电脑的内存吧! 1.在说到win7电脑内存合理管理之前,我们还需要涉及一个概念,那便是虚拟内存了,虚拟内存是相对物理内存而言的,也是咱们需要预留的一部分内存,因为足够大的虚拟内存可

Umdhtools.exe: 如何使用 umdh.exe 来查找内存泄漏

使用 UMDH 之前 如果您认为您遇到内存泄漏, 应注意, 内存泄漏可能不它们似乎什么. 您可能发现内存泄漏是不满足内存泄漏, 但是性能增强. 例如, MicrosoftJet 数据库引擎会消耗大量内存因为它检索数据并写入缓存 256 - MB 计算机上 (最多 128 MB). 缓存允许 Jet 引擎以获得快速读和写提前缓冲. 要确定是否是一个进程遇到内存泄漏, 使用 Windows 性能监视器 (Perfmon.exe) 并为应用程序进程类别下监视专用字节. 专用字节是总内存, 进程已分配,

LINUX类主机JAVA应用程序占用CPU、内存过高分析手段

转载声明:本文为DBA+社群原创文章,转载必须连同本订阅号二维码全文转载,并注明作者名字及来源:DBA+社群(dbaplus).   做为一个IT运维人员,通常在运维过程中会遇到各种各样的问题,系统问题.应用问题.程序问题,而在这当中必然会涉及到性能问题,当用户量过大,或者服务器性能不足以支持大用户量,但同时又得不到扩容的情况下,进行性能分析,并对系统.应用.程序进行优化则显得尤为重要,同时也是节省资源的一种必不可少的手段,目前大多数的运维产品都是基于JAVA语言开发的,下面我给大家介绍一下在l

如何定位 Node.js 的内存泄漏

基础知识 Node.js 进程的内存管理,都是有 V8 自动处理的,包括内存分配和释放.那么 V8 什么时候会将内存释放呢? 在 V8 内部,会为程序中的所有变量构建一个图,来表示变量间的关联关系,当变量从根节点无法触达时,就意味着这个变量不会再被使用了,就是可以回收的了. 而这个回收是一个过程性的,从快速 GC 到 最后的 Full GC,是需要一段时间的. 另外,Full GC 是有触发阈值的,所以可能会出现内存长期占用在一个高值,也可以算是一种内存泄漏,可以从<一次 Node.js 应用内