求解:界面画图刷新部分占用过多CPU资源问题??急啊。。。。

KennyXiao 2010-10-23 09:34:44
用C#开发的应用程序因为占用过多的CPU资源(有时候达到90%)导致系统"假死",也就是有那么几秒钟甚至一分钟,点击应用程序的界面,都没有反应,要等一会儿才有反应.

出现这种情况时候,我发现在任务管理器里面,该应用程序的页面错误增量和页面错误都较大,页面错误增量达2000k---3000k,而页面错误则已经累积达到 几千万K 了....不知道是否是这个原因导致的.....汗.....


该应用程序和外界的交互有,读写OPC,读写数据库,记录文本日志,发送Socket消息..除此外,系统内还有画图刷新处理..


该问题已经困惑很久了,,一直没有找到解决方法,,望各位能够指点迷津啊...不胜感激!!!!!!!!!!!!!!!


我觉得是 画图处理部分所导致(不知道是不是graphics没有调用 Dispose()啊???),,但是我确找不到根本的原因和解决办法啊..能否说教说教啊.呵呵

先介绍介绍我程序内部的大致处理:

画图集中在 Monitor.cs类里面,初始化的时候设置了双缓冲画图方式:
SetStyle(ControlStyles.DoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint,
true);
UpdateStyles();

在运行过程 Monitor 类作为 观察者 来接收其他对象状态的变化:
/// <summary>
/// 重写通知状态变化
/// </summary>
/// <param name="state">状态数据</param>
public override void SendNotify(object state)
{
...
}

接收到状态变化后,就进入了画图,都是以下处理方式:

#region " 主线订单号变化信息"
/// <summary>
/// 更新主线定单状态
/// </summary>
/// <param name="state"></param>
private void UpdateMainLineOrderState(ArrayList state)
{
mainLineOrderQueue.Enqueue(state);
if (deviceProcess != null)
{
deviceProcess.ChangeState(new StateChangedDelegate(DoUpdateMainLineOrderState));
}
}


/// <summary>
/// 更新主线定单状态
/// </summary>
private void DoUpdateMainLineOrderState()
{
MethodInvoker doDoUpdateMainLineOrderStateDelegate = new MethodInvoker(DoUpdateMainLineOrderStateDelegate);
if (InvokeRequired)
{
Invoke(doDoUpdateMainLineOrderStateDelegate);
}
else
{
doDoUpdateMainLineOrderStateDelegate();
}
}

/// <summary>
/// 更新主线定单状态
/// </summary>
private void DoUpdateMainLineOrderStateDelegate()
{
ArrayList bdA = mainLineOrderQueue.Dequeue() as ArrayList;
using (Graphics graphics = CreateGraphics())
{
DrawMainLineOrderState(bdA, graphics);
}
}

private void DrawMainLineOrderState(ArrayList state, Graphics graphics)
{
try
{
// state 所包含的项:第几位|值|画图区域|TruePic|FalsePic|className
string pic = state[3].ToString();
Bitmap bmp = new Bitmap(pic);


// Bitmap bmp = state[4] as Bitmap;
Rectangle range = (Rectangle)state[2];
string className = state[5].ToString();

float x = range.X - 2;
float y = range.Y ;
graphics.SetClip(range);

if (int.Parse(state[1].ToString()) > 0)
{
if (pic.Equals(""))
{
graphics.FillRectangle(new SolidBrush(BadColor), range);
}
else if (File.Exists(pic))
{
bmp = new Bitmap(pic);
bmp.MakeTransparent(Color.White);
graphics.DrawImage(bmp, range); ///是这个地方的 graphics 没有调用 Dispose()释放资源吗????
Font wordsFont = new Font (Font.FontFamily,8.0f);
Brush wordsBrush = Brushes.Black;

graphics.DrawString(state[1].ToString(), wordsFont,wordsBrush,x,y);
}
}
else
{
if (bmp == null)
{
graphics.FillRectangle(new SolidBrush(GoodColor), range);
}
else
{
graphics.DrawImage(bmp, range); ///是这个地方的 graphics 没有调用 Dispose()释放资源吗????}

}

}
catch(Exception ex)
{
MessageBox.Show(ex.Message + ex.ToString());
}
}

然后,Monitor 类
/// <summary>
/// 重写重画方法
/// </summary>
/// <param name="e">画图参数对象</param>
protected override void OnPaint(PaintEventArgs e)
{
if (!Visible || !canUpdate) return;
Graphics graphics = e.Graphics;
Draw(graphics);
base.OnPaint(e);
}

在 Draw(graphics)方法里面,调用DrawMainLineOrderState(graphics);如下所示.


/// <summary>
/// 画主线定单状态
/// </summary>
/// <param name="graphics">画图对象</param>
private void DrawMainLineOrderState(Graphics graphics)
{

if (this.mainlineOrderCollection == null) return;

for (int i = 0; i < mainlineOrderCollection.Length; i++)
{
if (mainlineOrderCollection[i] != null)
{
// storeState 所包含的项:第几位|值|画图区域|TruePic|FalsePic|className
ArrayList storeState = new ArrayList();
storeState.Add(mainlineOrderCollection[i].No);
storeState.Add(mainlineOrderCollection[i].SerialNo);
storeState.Add(mainlineOrderCollection[i].Range);
storeState.Add(mainlineOrderCollection[i].TruePic);
storeState.Add(mainlineOrderCollection[i].FalsePic);
storeState.Add(mainlineOrderCollection[i].ClassName);



DrawMainLineOrderState(storeState, graphics);
}
}
}



#endregion
...全文
149 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
KennyXiao 2010-10-26
  • 打赏
  • 举报
回复

先谢谢各位的回帖.

目前看来有 2 种解决方法:

第 1 种: 用 Timer 定时绘制.

dylike,xiaofeihu112: 请问这个 Timer 定时器用在什么位置, 是把重画部分 OnPaint()?还是所以画图部分?
能否给一个参考案例啊..我的邮箱是 : xzy_hello@163.com..多谢啊..




第 2 种: 用层窗体吧.毕竟直接在.NET窗体上绘制很慢.

dylike: 目前我的程序里面是在自定义控件上画图,然后这个控件是加载到主窗体上的.

请问 层窗体 是怎么使用的啊?能否给一个参考案例啊..我的邮箱是 : xzy_hello@163.com..多谢啊..


有一点想说明一下,,因为本人的程序已经使用在多个地方了,,所以如果是实在没有办法了,再大改,,当然在现有的情况下,,如果有更好的办法当然最好了..


另外,我上面说的 是不是graphics 没有调用 Dispose()释放资源吗?,这个有很大影响吗?还是可以不用考虑啊.因为我画图的方式都是上述代码的处理方式,,但是有10种多对象需要画图,,如果每个都没有调用 Dispose()释放资源,也会导致系统"假死"现象???




feitianhu112 2010-10-23
  • 打赏
  • 举报
回复
还是定时比较好,
dylike 2010-10-23
  • 打赏
  • 举报
回复
如果需要高速绘制,就不能使用普通窗体了,用层窗体吧.毕竟直接在.NET窗体上绘制很慢的.
相关:
updatelayeredwindow
KennyXiao 2010-10-23
  • 打赏
  • 举报
回复
dylike:

实际应用需要实时的点状态的信息啊,,你说的用Timer定时绘制,是制所有的画图吗?还是只针对重画部分?

是不是graphics 没有调用 Dispose()释放资源吗?,这个有很大影响吗??因为我的主界面,正常运行差不多有50---60 个点来实时绘制,,这些点数应该也不算多啊,郁闷中啊.........................

而且现在项目比较急,,急需解决这个问题啊....

还请你多指教指教啊...

看怎么改比较好啊...
dylike 2010-10-23
  • 打赏
  • 举报
回复
画得太快了.用TIMER定时绘制吧.
lifeixie 2010-10-23
  • 打赏
  • 举报
回复
这个操作资源很大的。你这么速度加高资源的直接绘,看着似乎有些问题。

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧