为什么有时我得到异常indexoutorange
本文关键字:异常 indexoutorange 为什么 | 更新日期: 2023-09-27 18:03:06
这是一个计时器滴答事件里面我得到每个进程的内存使用情况。在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'发生在自动化。exe,但未在用户代码中处理
附加信息:索引在数组边界之外
系统。用户代码未处理IndexOutOfRangeException
而且它只发生一次到多次。大多数情况下,异常不显示。
当我把鼠标放在光标上,然后在计数上,我看到:
Count =由于前一个函数而禁用函数求值评估超时。您必须继续执行以重新启用功能评估。
设置定时器间隔1000ms。
不确定这意味着什么,我必须继续执行以重新启用函数求值。以及如何修复它。为什么有时会有例外,而大多数情况下没有?
我根据丹的回答改变了我的代码,但现在在另一个地方得到异常。这是新的代码:
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 '的异常。InvalidOperationException'在System.dll中发生,但未在用户代码中处理
附加信息:实例'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:
下面是与您的问题相关的三行重要代码:
procList = Process.GetProcesses().ToList();
Process[] processes = Process.GetProcessesByName(procList[i].ProcessName);
performanceCounter.InstanceName = processes[0].ProcessName;
你在这里做的是
- 获取所有进程的列表
- 获取与第一个列表中进程名称相同的进程列表
- 获取第二个列表中第一个进程的名称
忽略这里的冗余,问题是时间问题。
假设您有一个进程foo.exe
正在运行。这个过程出现在步骤1的列表中。如果该过程在步骤1和步骤2之间终止,则步骤2中foo.exe
的列表将为空。当列表为空时调用processes[0]
将抛出您所看到的异常。
为了避免这种情况,我建议您完全避免步骤2:您已经检索了所有流程的信息,因此使用您已经拥有的数据。这样做的好处可能是加快代码的速度!
可能没有进程具有您正在查找的名称。当这种情况发生时,processes
的长度将为0,并且没有有效的指标。所以不管你在括号里输入什么数字,你都会得到一个IndexOutOfRangeException
。
要解决这个问题,您应该确保在使用processes
数组之前存在匹配进程:
//...
Process[] processes = Process.GetProcessesByName(procList[i].ProcessName);
if (processes.Length > 0) {
// ...
performanceCounter.InstanceName = processes[0].ProcessName;
还有其他一些方法可以实现这个目标,但这应该为您指明了正确的方向。
在循环过程中,如果进程结束,将抛出异常…