CPUAlert:拯救您的 CPU 免于过热和电池过快耗尽






4.74/5 (18投票s)
CPUAlert 监控进程的 CPU 和内存消耗,
- 下载源代码 (版本-1.0.2) - 515.37 KB
- 下载 CPUMonitor.Setup - 198.88 KB
- 从 http://code.google.com/p/cpualert/ 下载最新版本的代码和安装程序

引言
如果您的计算机运行过热或电池电量消耗过快,那很可能是由于某个应用程序或进程占用了大量CPU或内存。如果您长时间运行应用程序,例如 Outlook,它会持续增加内存消耗并且不会有效释放内存。结果,您的计算机物理内存耗尽,其他应用程序运行缓慢。有时,Outlook、浏览器、图像编辑应用程序或其他一些应用程序会进入某个无限循环,导致它们占用全部CPU,使您的CPU过热,并且您的应用程序性能变得迟钝。
CPUAlert
是一款监视应用程序CPU和内存消耗的应用程序,如果某个应用程序持续占用高CPU或高内存,它会向您发出警报。它不仅能节省您的CPU和电池寿命,还能使您的计算机运行顺畅,让您的活动应用程序运行尽可能快。
如何使用该应用程序
运行时,如果某个进程占用了超过 200 MB 的内存,它会显示一个警报
在这里您可以看到我的 Outlook 占用了 244 MB 的物理 RAM。
您可以选择推迟警报 5 分钟(只需按 ESC 键),或永久忽略该进程,这样您就不会再收到该进程的警报,或者您可以关闭它并回收内存。
一个方便的功能是“重启”,它会关闭应用程序并重新启动。这通常会释放被进程占用的内存。
如果某个进程持续占用超过 30% 的 CPU 超过 5 分钟,也会出现相同的警报。
您可以通过右键单击任务栏图标并选择“设置”来配置所有这些设置,例如 CPU 和内存的可接受限度、警报频率、关闭应用程序前的等待时间等。
该应用程序会注册以在 Windows 启动时启动。如果您想从 Windows 启动中删除它,只需从“开始菜单”->“所有程序”->“启动”菜单中删除应用程序快捷方式即可。
Using the Code
CPU Alert 是一个小项目。重要的文件有
- MonitorCPUForm.cs:这是应用程序启动时加载的主窗口。它隐藏在系统托盘中,并在后台运行应用程序。它还包含一个“设置”视图,允许您更改 CPU 和内存阈值、警报间隔等。它还协调操作并显示必要的警报。
- KillProcessForm.cs:它只有上面弹出窗口中显示的警报的用户界面。没有智能。
- Monitor.cs:这是执行监视、测量 CPU 和内存使用情况并触发警报的重要类。如果您想在您的应用程序中拥有此类功能,可以重用此类。
我们先来看一下 Monitor.cs 类,它具有监视 CPU 和内存的智能。它使用 WMI 来监视进程。我最初尝试使用 Process
类并尝试访问 TotalProcessorTime
,但对于 mysqld
等进程,我收到了“访问被拒绝”的错误。对于某些进程,我无法获得 WorkingSet
等信息。然后我尝试使用 PerformanceCounter
来获取进程的 CPU 和内存使用情况。为每个进程查询 Performance Counter 的开销太大了。所以,我不得不依赖 WMI 来提供信息。
private ManagementObjectSearcher _Searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT IDProcess, Name, PercentProcessorTime, Description,
WorkingSet FROM Win32_PerfFormattedData_PerfProc_Process");
.
.
.
private List<ProcessInfo> GetUsage()
{
var processes = new List<ProcessInfo>();
foreach (ManagementObject queryObj in _Searcher.Get())
{
var process = new ProcessInfo
{
Id = Convert.ToInt32(queryObj["IDProcess"]),
Name = Convert.ToString(queryObj["Name"]),
CpuUsage = Convert.ToInt32(queryObj["PercentProcessorTime"]),
Description = Convert.ToString(queryObj["Description"]),
WorkingSet = Convert.ToInt64(queryObj["WorkingSet"]),
};
if (string.IsNullOrEmpty(process.Description))
process.Title = process.Name;
else
process.Title = process.Description;
if (process.Id > 0)
processes.Add(process);
}
return processes;
}
非常直接。这里唯一值得学习的酷炫之处是,我将 ManageObjectSearcher
声明为该函数的 `private` 变量,而不是局部变量,因为似乎每次调用 GetUsage
函数时创建和销毁它都非常昂贵。每次我尝试创建和销毁搜索器时,CPU 在 WMIpserv.exe
上会花费大约 30 秒钟占用 20% 的 CPU。
关闭进程成了一个研发挑战。您可以通过调用 Process.Kill
来终止一个进程,但这会异常终止进程。如果您以这种方式终止 Outlook,会导致数据损坏。所以,您必须优雅地关闭应用程序。然而,如果某个应用程序卡住了并占用了 100% 的 CPU,尝试优雅地关闭它不起作用。您必须采取激进措施。在这种情况下,杀死它才是唯一的解决方案。
所以,我首先尝试温和地关闭进程
/// <summary>
/// Closes the process by sending Shutdown message to the main window.
// Then it starts a timer to check if the process is really closed.
/// </summary>
/// <param name="processToKill">The process to kill.</param>
private void CloseProcess(ProcessInfo processToKill)
{
try
{
Process process = Process.GetProcessById(processToKill.Id);
processToKill.Path = process.MainModule.FileName;
process.CloseMainWindow();
}
catch (Exception closeException)
{
if (MessageBox.Show(this, "Unable to close process: "
+ (processToKill.Title) + Environment.NewLine
+ closeException.Message + Environment.NewLine
+ "Do you want to kill it?", "Unable to close process",
MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
{
KillProcess(processToKill);
}
}
// Check back after a while if the process is still running.
//If it's running kill it
CheckAfterAWhileIfItsStillRunning(processToKill);
}
这里它调用 Process.CloseMainWindow
函数向进程发送一个关机消息。如果进程有一个可见窗口,它将收到消息并希望它很快关闭。如果没有可见窗口,它将不会收到消息也不会关机。所以,我们必须杀死它。
即使某个进程收到了关机消息,如果它卡在某个无限循环中,也可能无法正确终止。在这种情况下,我们需要稍后检查它是否仍在运行,然后杀死它。
private void KillProcess(ProcessInfo processToKill)
{
try
{
foreach (Process process in Process.GetProcessesByName(processToKill.Name))
{
// Check if the process is still running
if (process.Id == processToKill.Id)
{
if (!process.HasExited)
{
process.Kill();
process.Close();
}
}
}
// If user has requested the process to be restarted, then restart it.
if (processToKill.CanRestart)
Process.Start(processToKill.Path);
}
catch (Exception killException)
{
MessageBox.Show(this, "Unable to kill process: "
+ (processToKill.Title)
+ Environment.NewLine + "You should restart your computer",
"Unable to kill process",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
这个函数是从一个计时器触发的。我们等待一段时间,然后执行杀死操作。首先检查进程是否还在运行。如果是,则杀死它。
另一个有趣的话题是内存使用。如您所知,Windows Forms 应用程序启动时会占用大约 10 MB 到 15 MB 的内存。对于一个正在后台运行并试图为您节省内存的实用程序来说,这太多了。这是因为当 .NET WinForms 库加载时,它们会加载大量内容,希望您会用到它,从而节省额外的加载时间。所以,我不得不强迫 .NET 清理任何未使用的东西。我有一个 MemoryHelper
来做这件事。
static class MemoryHelper
{
[DllImport("psapi.dll")]
static extern int EmptyWorkingSet(IntPtr hwProc);
public static void ClearMemory()
{
try
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
EmptyWorkingSet(Process.GetCurrentProcess().Handle);
}
catch
{
}
}
}
首先它强制进行垃圾回收,然后调用 psapi.dll
上的 EmptyWorkingSet
函数来刷新工作集,即物理内存分配。我不知道它是否有效,但至少任务栏显示该应用程序现在只占用 5 MB 内存。太棒了!
结论
希望 CPUAlert
能帮助您避免 PC 变慢或笔记本电脑电池过快耗尽。如果您觉得它有用,请传播出去。首先给这篇文章投票。
历史
- 2010 年 3 月 2 日:首次发布