这是一个计时器刻度事件,我正在获取每个进程内存使用情况。 在95%的情况下,它工作得更好,我尝试了20次运行我的程序,直到异常抛出。
在表单的顶部:
System.Timers.Timer aTimer = new System.Timers.Timer();
然后在构造函数中:
aTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 1000;
然后计时器已经过了事件:
Image ima = null;
private void OnTimedEvent(object source, System.Timers.ElapsedEventArgs e)
{
List<MyProgress> prog = new List<MyProgress>();
prog = new List<MyProgress>();
DoubleBufferedd(dataGridView1, true);
procList = Process.GetProcesses().ToList();
for (int i = 0; i < procList.Count; i++)
{
Process[] processes = Process.GetProcessesByName(procList[i].ProcessName);
PerformanceCounter performanceCounter = new PerformanceCounter();
performanceCounter.CategoryName = "Process";
performanceCounter.CounterName = "Working Set - Private";
performanceCounter.InstanceName = processes[0].ProcessName;
try
{
var icon = Icon.ExtractAssociatedIcon(processes[0].MainModule.FileName);
ima = icon.ToBitmap();
ima = resizeImage(ima, new Size(25, 25));
ima = (Image)(new Bitmap(ima, new Size(25, 25)));
}
catch
{
}
prog.Add(new MyProgress { Id = procList[i].Id, Progress = ((uint)performanceCounter.NextValue() / 1024).ToString("N0"), ProcImage = ima, ProcessName = procList[i].ProcessName });
}
BeginInvoke((Action)(() =>
{
List<MyProgress> list = prog;//new List<MyProgress>();
foreach (MyProgress p in list)
{
DataGridViewRow row;
if (!processRows.TryGetValue(p.Id, out row))
{
int index = dataGridView1.Rows.Add(p.ProcImage, p.ProcessName, null, p.Progress);
row = dataGridView1.Rows[index];
processRows.Add(p.Id, row);
}
else
{
row.Cells[3].Value = p.Progress;
}
}
foreach (int id in processRows.Keys.Except(list.Select(p => p.Id)).ToArray())
{
dataGridView1.Rows.Remove(processRows[id]);
processRows.Remove(id);
}
}));
}
当异常发生时,它就在线上:
performanceCounter.InstanceName = processes[0].ProcessName;
发生了'System.IndexOutOfRangeException'类型的异常 Automation.exe但未在用户代码中处理
其他信息:索引超出了数组的范围
System.IndexOutOfRangeException未被用户代码
处理
它只发生过一次或多次。大部分时间都没有显示异常。
当我把鼠标放在proclist上然后在Count上我看到:
Count =由于之前的功能而禁用了功能评估 评估超时。您必须继续执行以重新启用功能 评价。
计时器的间隔设置为1000毫秒。
不确定是什么意思我必须继续执行以重新启用功能评估。以及如何解决它。 为什么有时它确实会成为例外而在大多数情况下都没有?
我根据Dan的回答更改了我的代码,但现在又在另一个地方获得了异常。 这是新代码:
Image ima = null;
private void OnTimedEvent(object source, System.Timers.ElapsedEventArgs e)
{
List<MyProgress> prog = new List<MyProgress>();
prog = new List<MyProgress>();
DoubleBufferedd(dataGridView1, true);
procList = Process.GetProcesses().ToList();
for (int i = 0; i < procList.Count; i++)
{
PerformanceCounter performanceCounter = new PerformanceCounter();
performanceCounter.CategoryName = "Process";
performanceCounter.CounterName = "Working Set - Private";//"Working Set";
performanceCounter.InstanceName = procList[i].ProcessName;
try
{
var icon = Icon.ExtractAssociatedIcon(procList[i].MainModule.FileName);
ima = icon.ToBitmap();
ima = resizeImage(ima, new Size(25, 25));
ima = (Image)(new Bitmap(ima, new Size(25, 25)));
}
catch
{
}
prog.Add(new MyProgress { Id = procList[i].Id, Progress = ((uint)performanceCounter.NextValue() / 1024).ToString("N0"), ProcImage = ima, ProcessName = procList[i].ProcessName });
}
BeginInvoke((Action)(() =>
{
List<MyProgress> list = prog;
foreach (MyProgress p in list)
{
DataGridViewRow row;
if (!processRows.TryGetValue(p.Id, out row))
{
int index = dataGridView1.Rows.Add(p.ProcImage, p.ProcessName, null, p.Progress);
row = dataGridView1.Rows[index];
processRows.Add(p.Id, row);
}
else
{
row.Cells[3].Value = p.Progress;
}
}
foreach (int id in processRows.Keys.Except(list.Select(p => p.Id)).ToArray())
{
dataGridView1.Rows.Remove(processRows[id]);
processRows.Remove(id);
}
}));
}
我不再使用Process []流程了。
并更改了两行以使用procList:
这行我正在使用procList [I]
performanceCounter.InstanceName = procList[i].ProcessName;
此行我正在使用procList [I]
var icon = Icon.ExtractAssociatedIcon(procList[i].MainModule.FileName);
但现在我在线上遇到例外:
prog.Add(new MyProgress { Id = procList[i].Id, Progress = ((uint)performanceCounter.NextValue() / 1024).ToString("N0"), ProcImage = ima, ProcessName = procList[i].ProcessName });
出现InvalidOperationException
System.dll中出现'System.InvalidOperationException'类型的异常,但未在用户代码中处理
其他信息:实例'SearchFilterHost'在指定的类别中不存在。
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=Instance 'SearchFilterHost' does not exist in the specified Category.
Source=System
StackTrace:
at System.Diagnostics.CounterDefinitionSample.GetInstanceValue(String instanceName)
at System.Diagnostics.PerformanceCounter.NextSample()
at System.Diagnostics.PerformanceCounter.NextValue()
at Automation.Form1.OnTimedEvent(Object source, ElapsedEventArgs e) in d:\C-Sharp\Automation\Automation\Automation\Form1.cs:line 805
at System.Timers.Timer.MyTimerCallback(Object state)
InnerException:
答案 0 :(得分:2)
以下是与您的问题相关的三个重要代码行:
procList = Process.GetProcesses().ToList();
Process[] processes = Process.GetProcessesByName(procList[i].ProcessName);
performanceCounter.InstanceName = processes[0].ProcessName;
你在这里做的是
忽略这里的冗余,问题是时间问题。
假设您正在运行进程foo.exe
。该过程显示在步骤1的列表中。如果该流程应在步骤1和2之间终止,则foo.exe
的步骤2中的列表将为空。列表为空时调用processes[0]
将抛出您已经看过的异常。
为避免这种情况,我建议您完全避免第2步:您已经检索了所有流程的信息,因此请使用您已有的数据。这可能会加快您的代码速度!
答案 1 :(得分:0)
可能没有具有您要查找的名称的进程。发生这种情况时,processes
的长度为0,并且没有有效的索引。因此,无论您在括号中输入什么数字,都会获得IndexOutOfRangeException
。
要解决此问题,您应该在使用processes
数组之前确保匹配的进程:
//...
Process[] processes = Process.GetProcessesByName(procList[i].ProcessName);
if (processes.Length > 0) {
// ...
performanceCounter.InstanceName = processes[0].ProcessName;
还有一些其他方法可以实现这一目标,但这应该指向正确的方向。
答案 2 :(得分:0)
在循环期间,如果进程结束,将抛出异常...