C# 关于进程回收管理的一款工具设计与分享

目录

设计初衷

开发运行环境

Craneoffice ProcessGC

运行主界面

管理任务与策略

其它设置

移动存储设备管理

核心代码-计时器监控

小结


设计初衷

在使用 COM 模式操作 OFFICE 组件的开发过程中,当操作完相关文档后,在某些情况下仍然无法释放掉 Word 或 EXCEL 等应用进程,因此根据进程活动情况或时间点范围开发了一个强制杀掉指定进程名称的 WinForm 程序,做为一种辅助工具运行在云服务器上,命名为 Craneoffice ProcessGC。

开发运行环境

操作系统: Windows Server 2019 DataCenter

.net版本: .netFramework4.0 或以上

开发工具:VS2019  C#

Craneoffice ProcessGC

该工具软件属绿色版,无须安装,直接运行 bin 目录下的 ProcessGC.exe 即可,同目录下的 ProcessList.txt 为配置文件,用于配置要释放的进程,后续也可用工具程序进行操作。

运行主界面

运行后的主界面如下图:

主界面显示了要回收的进程列表,源引于 ProcessList.txt 文件配置,如图示例我们可以看到欲回收的进程为EXCEL和WORD,下面则显示已被回收的进程(如果有的话)。

下方显示 CPU 的利用率和可用内存情况。

系统会随时监测指定的进程名,如果有则按指定的策略进行管理。

管理任务与策略

点击管理任务选项卡,显示如下图:

策略设置如下表:

序号说明
1要添加回收的进程名请正确添加,无须输入扩展名,如果不确定名称则可以通过任务管理器进行查看
2管理策略

共分三种方式:

1、Force(默认值,表示符合条件则强制关闭)

2、CPU

3、Memory

3回收时间差(秒)以秒为单位,记录进程停止活动的时间,超过停止活动时间的进程将被回收
4上限指标

1、上限指标不能小于零。

2、当选用的策略为CPU时,上限指标不能大于100(即最高100%占用率)

3、当选用的策略为Memory时,指定为Mb值,表示内存占用的最高上限

5检测时间标准

共有两种方式:

1、ByProcess,以进程时间计算(默认)

2、ByNowTime,以启动当前时间计算

6回收动作

共有两种方式:

1、Kill,直接关闭释放进程(默认)

2、Command,执行命令行操作

7相关动作命令当第6项回收动作为Command时,此项为必输入项,表示要执行的 WINDOWS 命令行操作
8重新启用命令设置此项,则当关闭或执行动作命令后,尝试执行此命令
9计划强制关闭时间(小时)可以设定小时:分:秒(这个值前缀需要设置一个有效日期),代表每到此时此分此秒,则强制关闭进程

通过以上设置,我们可以灵活的对进程的关闭方式进行控制,以达到实际应用的目的。

其它设置

选择设置选项卡,如下图:

我们可设置窗口的透明度,另外可以设置两个选项:

1、只回收本程序启动时间以后的进程

2、只回收非激活窗口的进程, 指非操作系统显式的应用进程。

3、管理密码:默认值为111111,用于关闭应用程序等操作。

移动存储设备管理

这个选项如下图:

这是为移动设备存储数据库准备的一个选项,点击停止服务可以有效的、安全的移除存储设备,也可以继续启动服务。这个选项较少使用,也需要谨慎使用(因为它会尝试停止IIS、MS SQL SERVER 数据库服务等)。

核心代码-计时器监控

		private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			DateTime cur_now=System.DateTime.Now;
			int cur_hour=cur_now.Hour;
			int cur_min=cur_now.Minute;
			int cur_sec=cur_now.Second;
		
			pc.CategoryName="Processor";
			pc.CounterName="% Processor Time";
			pc.InstanceName="_Total";
			
//			pc.MachineName="michaeljane";
			float pcv=pc.NextValue();
			label7.Text="CPU利用率:"+(pcv).ToString()+" %";
			cpubar.Value=(int)(pcv);

			pcmem.CategoryName="Memory";
			pcmem.CounterName="Available MBytes";
			pcmem.InstanceName=null;

//			richTextBox1.Text=pcpu.NextValue().ToString()+"\r\n";
			

			/*			System.Diagnostics.PerformanceCounter[] mypc; 
			System.Diagnostics.PerformanceCounterCategory mycat = 
				new System.Diagnostics.PerformanceCounterCategory("process");
			// Remove the current contents of the list.
			// Retrieve the counters.
			mypc = mycat.GetCounters();
			// Add the retrieved counters to the list.
			richTextBox1.Text="";
			for (int i = 0; i < mypc.Length; i++) 
			{ 
				richTextBox1.Text+=(mypc[i].CounterName)+"\r\n";
			}
*/

//			float cpuLoad = pc.NextValue();
            try
            {
                label7.Text += "\r\n可用内存:" + pcmem.NextValue().ToString() + "M";
            }
            catch (Exception s)
            {
            }
			statusBar1.Text=cur_now.ToString();  //显示当前时间
			Process[] processes; //定义进程组
			processes = System.Diagnostics.Process.GetProcesses(); //获得当前进程组
			Process process;  //定义初始进程中间变量
			string _pname,_killstate="";   //定义进程名变量,及进程回收状态字符串
			bool _kill=false;  //是否要回收标志变量
			bool _phandle=checkBox2.Checked;
			int _gcSpan;  //时间差变量
			DateTime _pdatetime,_checktime,_stdtime; //进程启动的时间变量和检测时间变量
			string[] _rv;    //接受检测结果的数组
			System.TimeSpan _dd; //时间差的秒数变量
//			string[] _processid=new string[1000];
//			DateTime[] _processLastTime=new DateTime[1000];
//			int[] _processLastMem=new int[1000];
				for(int i = 0;i<processes.Length-1;i++)
				{
					process= processes[i];  //获得当前进程
					_pname=process.ProcessName.ToLower();  //获得进程名并转为小写
                try
                {
                    _pdatetime = process.StartTime;  //获得进程的启动时间
                }catch(Exception e1)
                {
                    continue;
                }
					//				_rv=GetSubValueIndex(listBox1,_pname,"|");  //得到要回收的用户指定进程
					for(int li=0;li<listBox1.Items.Count;li++)
					{
						_rv=listBox1.Items[li].ToString().Split('|');
						string ref_process=_rv[0].ToLower().Trim();
						int ref_span=int.Parse(_rv[1].ToString());
						string ref_cl=_rv[2].ToLower().Trim();
						float ref_rank=float.Parse(_rv[3].ToString());
						string ref_stdtime=_rv[4].ToLower().Trim();
						string ref_act=_rv[5].ToLower().Trim();
						string[] ref_cmd1=_rv[6].Split('↙');
						string[] ref_cmd2=_rv[7].Split('↙');
						string ref_closetime=_rv[8].Trim();
						//				richTextBox1.Text+=_rv[0]+_rv[1]+"\r\n";
					
						if(ref_process==_pname)  //如果是要回收的进程则进行处理
						{
							//如果在检测数组没有找到,则添加到检测数中
							int _curpoint=System.Array.IndexOf(_processid,process.Id);
							if(_curpoint<0)
							{
								_stdtime=process.StartTime;
								if(ref_stdtime=="bynowtime")
								{
									_stdtime=System.DateTime.Now;
								}
								System.Diagnostics.PerformanceCounter pcm=new System.Diagnostics.PerformanceCounter("Process","% Processor Time",_pname);
                            try
                            {
                                AddArray(process.Id, _stdtime, process.WorkingSet, pcm);
                            }catch(Exception e3)
                            {

                            }
								continue;
							}
                        //						richTextBox1.Text+=((System.Diagnostics.PerformanceCounter)_processLastCPU[_curpoint]).NextValue().ToString()+"\r\n";
                        try
                        {
                            float cur_rank = ((System.Diagnostics.PerformanceCounter)_processLastCPU[_curpoint]).NextValue();
                            _checktime = System.DateTime.Now;  //检测时间为当前时间
                                                               //开始分析CPU策略
                            if (ref_cl == "cpu")
                            {
                                //如果当前进程的CPU占用率没有超过指定的上限,则重置最后的检测时间为当前时间,继续监测。
                                if (cur_rank < ref_rank)
                                {
                                    _processLastTime[_curpoint] = _checktime;
                                }
                            }
                        }catch(Exception e2)
                        {
                            continue;
                        }
							//开始分析memory策略
							if(ref_cl=="memory")
							{
								float _curmem=process.WorkingSet/(1024*1024);
								//							richTextBox1.Text+=_pname+" "+_curmem.ToString()+"\r\n";
								//如果当前进程的内存占用没有超过指定的上限,则重置最后的检测时间为当前时间,继续监测。
								if(_curmem<ref_rank)
								{
									_processLastTime[_curpoint]=_checktime;
								}
							}
							_gcSpan=ref_span;  //得到用户指定的回收时间差
							_kill=false;
							_pdatetime=_processLastTime[_curpoint]; //得到进程的数组最后指定时间
							_dd=_checktime-_pdatetime;     //时间差以检测时间 减去 进行启动时间
							//如果时间差大于回收指定时间则可以回收进程,KILL变量为真
							if(checkBox1.Checked)
							{
								//只回收本程序启动以后的进程时间
								if((_dd.TotalSeconds>_gcSpan)&&(_starttime<_pdatetime))
								{
									_kill=true;
								}
							}
							else
							{
								if(_dd.TotalSeconds>_gcSpan)
								{
									_kill=true;
								}
							}
							//如果初期标识为可以关闭该进程,并且策略为强制性关闭,则进行内存判断
							if((_kill)&&(ref_cl=="force"))
							{
								//如果内存有变化,则表示进程仍在活动,则不进行关闭,并更新检测内容
								int _curmem=process.WorkingSet;
								label6.Text=_curmem.ToString()+"  "+_processLastMem[_curpoint];
								if(_curmem!=_processLastMem[_curpoint])
								{
									_processLastTime[_curpoint]=_checktime;
									_processLastMem[_curpoint]=_curmem;
									_kill=false;
								}
							}
							//如果指定了强制关闭时间,则进行判断
							string close_tip="";
							if(ref_closetime!="")
							{
								DateTime ref_cls=DateTime.Parse(ref_closetime);
								if((ref_cls.Hour==cur_hour)&&(ref_cls.Minute==cur_min)&&(ref_cls.Second==cur_sec))
								{
									_kill=true;
								    close_tip="强制关闭计划启动,计划时间为:"+ref_closetime;
								}
							}
							//如果只回收死进程,而当前进程为激活的窗口的话,则不关闭
							if((_phandle)&&((int)process.MainWindowHandle!=0))
							{
								_kill=false;
							}

							//如果可以回收则在文本框中添加回收状态,并将进程关闭
							if(_kill)
							{
								if(!process.HasExited)
								{
									if(ref_act=="kill")
									{
										//								MessageBox.Show("has exited");
										_killstate=close_tip+".进程"+_pname+"已被回收,关闭策略为"+ref_cl+",动作为:"+ref_act+"。进程的启动时间为"+
											_pdatetime.ToString()+",检测时间为:"+_checktime.ToString()+
											",现已经超时"+(_dd.TotalSeconds-_gcSpan).ToString()+
											"秒,回收时间单位是"+_gcSpan.ToString()+"秒。"+
											"进程ID:"+process.Id.ToString()+
											"进程主窗口句柄:"+process.MainWindowHandle.ToString();
										process.Kill();
										richTextBox1.AppendText(_killstate+"\r\n");
									}
									if(ref_act=="command")
									{
										//								MessageBox.Show("has exited");
										string _return="";
										for(int st=0;st<ref_cmd1.GetLength(0);st++)
										{
											_return+=ref_cmd1[st]+" Result:"+WinExec(ref_cmd1[st],0).ToString()+"↙";
										}
										_killstate=close_tip+".进程"+_pname+"已被回收,关闭策略为"+ref_cl+",动作为:"+ref_act+",执行了命令:"+
											ref_cmd1+"。返回值为:"+_return+"。进程的启动时间为"+
											_pdatetime.ToString()+",检测时间为:"+_checktime.ToString()+
											",现已经超时"+(_dd.TotalSeconds-_gcSpan).ToString()+
											"秒,回收时间单位是"+_gcSpan.ToString()+"秒。"+
											"进程ID:"+process.Id.ToString()+
											"进程主窗口句柄:"+process.MainWindowHandle.ToString();
										richTextBox1.AppendText(_killstate+"\r\n");
										//										process.Kill();
									}
									//清空当前进程检测数组元素
									_processid[_curpoint]=0;
									_processLastTime[_curpoint]=_checktime;
									_processLastMem[_curpoint]=0;
									_processLastCPU[_curpoint]=null;
								}//判断进程是否已经退出
							}
						}//if proecess
						else //如果没有找到进程名称,则二次判断任务是否提供了启动命令,如果提供,则运行它
						{
						}//end find process name
					}//li
				}//for
			processes = System.Diagnostics.Process.GetProcesses(); //获得当前进程组
			for(int ali=0;ali<listBox1.Items.Count;ali++)
			{
				_rv=listBox1.Items[ali].ToString().Split('|');
				string ref_process=_rv[0].ToLower().Trim();
				int ref_span=int.Parse(_rv[1].ToString());
				string ref_cl=_rv[2].ToLower().Trim();
				float ref_rank=float.Parse(_rv[3].ToString());
				string ref_stdtime=_rv[4].ToLower().Trim();
				string ref_act=_rv[5].ToLower().Trim();
				string[] ref_cmd1=_rv[6].Split('↙');
				string ref_start_cmd=_rv[7];
				string[] ref_cmd2=_rv[7].Split('↙');
				bool _find=false;
				if(ref_start_cmd!="")
				{
					for(int i = 0;i<processes.Length-1;i++)
				    {
					  process= processes[i];  //获得当前进程
					  string cur_pname=process.ProcessName.ToLower();  //获得进程名并转为小写
						if(cur_pname==ref_process)
						{
							_find=true;
						}
				    }
					if(!_find)
					{
						string _return="";
						for(int st=0;st<ref_cmd2.GetLength(0);st++)
						{
							_return+=ref_cmd2[st]+" Result:"+WinExec(ref_cmd2[st],0).ToString()+"↙";
						}
						_killstate="进程"+ref_process+"尝试启动,关闭策略为"+ref_cl+",动作为:"+ref_act+",启动命令为:"+
							ref_cmd2+"。返回值为:"+_return+"。";
						richTextBox1.AppendText(_killstate+"\r\n");
					}
				}
			}//end for listbox

		}

小结

开发这款小工具,也是初识 System.Diagnostics(与系统进程、事件日志和性能计数器进行交互的类)的一个过程。

这里可以下载完整源码:https://download.csdn.net/download/michaelline/89140846

工具仅作学习使用,大家感兴趣的话可以按照自己的需求进行修改,感谢您的阅读,希望本文能对您有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/545801.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】数据结构的恶龙set和map来了~

下一篇AVL树难点中的难点~ 文章目录 前言一、set的介绍二、map的介绍 题目练习总结 前言 1.关联式容器 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque、 forward_list(C11)等&#xff0c;这些容器统称为序列式容…

【C++】3.类和对象(中)

一、类的6个默认成员函数 在上一篇博客中&#xff0c;我们计算了空类的大小为 1 。那么空类中真的什么东西都没有吗&#xff1f;其实不是的&#xff0c;当一个类在什么都不写的时候就会自动生成6个默认的成员函数&#xff08;用户没有写&#xff0c;但是编译器自动生成的成员函…

AI在运维实践中的价值提升

在2024年的AI赛道上&#xff0c;利用大数据 、机器学习算法、人工智能来改善运维效率已成为软件运营商发展的新主张&#xff0c;通过AI在运维流程的洞察、决策和执行&#xff0c;从而提升效率、减少故障时间&#xff0c;优化用户体验。通过分析大量数据来识别趋势和模式&#x…

C ++ 和 C语言的优缺点分别是什么?

C语言&#xff0c;它简直就是编程世界的一块磐石。简洁、直接&#xff0c;让人一眼就能明白它想干嘛。它的运行速度快&#xff0c;接近硬件操作&#xff0c;特别适合那些需要直接与硬件打交道的场景。但就是因为这种接近硬件的特性&#xff0c;C语言在抽象层次上就显得有点捉襟…

科技感画册制作方法,视觉效果直接拉满

随着科技的不断进步&#xff0c;科技感画册制作也变得更加精彩和引人注目。通过巧妙地运用先进的设计工具和技术&#xff0c;以及结合创新的视觉元素&#xff0c;可以轻松地将画册的视觉效果直接拉满。 那你想知道怎么制作吗&#xff1f;现在我来教你这个方法吧&#xff0c;方法…

第九届少儿模特明星盛典 全球赛首席体验官『彭禹锦』精彩回顾

2024年1月30日-2月1日&#xff0c;魔都上海迎来了龙年第一场“少儿形体行业美育春晚”&#xff01;由IPA模特委员会主办的第九届少儿模特明星盛典全球总决赛圆满收官&#xff01;近2000名少儿模特选手从五湖四海而来&#xff0c;决战寒假这场高水准&#xff0c;高人气&#xff…

docker安装并跑通跑通QQ机器人实践(1)-前言及展示

随着大模型技术的迅猛发展&#xff0c;行业应用日益丰富且专业化。为了有效利用大模型的强大功能&#xff0c;建立与之紧密互动的应用接口至关重要。在此背景下&#xff0c;QQ、微信、钉钉等主流即时通讯工具凭借其广泛的用户覆盖和便捷的通信特性&#xff0c;成为连接用户与大…

CompletableFuture 处理异步异常

1、自定义线程池 Configuration public class ThreadPoolConfig {public static ThreadPoolExecutor getThreadPoolExecutor() {int availableProcessors Runtime.getRuntime().availableProcessors();return new ThreadPoolExecutor(availableProcessors,availableProcessor…

深入探索:Zookeeper+消息队列(kafka)集群

目录 前言 一、Zookeeper概述 1、Zookeeper概念 2、Zookeeper 特点 3、Zookeeper工作机制 4、Zookeeper 选举机制 4.1 第一次启动选举机制 4.2 非第一次启动选举机制 5、Zookeeper 数据结构 6、Zookeeper 应用场景 二、部署 Zookeeper 集群 1、环境部署 2、安装 z…

Linux进阶篇:linux操作系统一个神奇的分区:swap交换分区

linux操作系统一个神奇的分区&#xff1a;swap交换分区 1 Swap交换分区概念 Linux内核为了提高读写效率与速度&#xff0c;会将文件在内存中进行缓存&#xff0c;这部分内存就是Cache Memory(缓存内存)。即使你的程序运行结束后&#xff0c;Cache Memory也不会自动释放。这就…

macOS 待机一段时间后所有打开的应用会被退出

最近在使用MacBook电脑时&#xff0c;发现电脑在待机一段时间再登录进去时&#xff0c;发现所有打开的应用都被退出了&#xff0c;就跟刚开机一样&#xff0c;很影响使用体验&#xff0c;查找资料时发现有个设置被打开了&#xff0c;只需关闭这个设置就可以解决该问题&#xff…

数据结构--选择排序

1、选择排序 1.1 基本认识 1.1.1 基本概念 选择排序是一种简单直观的排序算法&#xff0c;无论什么数据进去都是 O(n) 的时间复杂度。 1.1.2 算法步骤 &#xff08;1&#xff09;首先在未排序序列中找到最小&#xff08;大&#xff09;元素&#xff0c;存放到排序序列的起…

Java并发--内存结构图及线程安全

内存结构图 内存-> (开辟的数组) -> (方法区&#xff0c;堆&#xff0c;栈&#xff0c;程序计数器&#xff0c;本地方法栈) 堆&#xff1a;几乎所有的对象实例都在这里分配内存。堆中每个对象的头信息都标属着他属于哪个类。 方法区它用于存储已被虚拟机加载的类型信息…

实现iOS App代码混淆

简介 在开发iOS应用程序时&#xff0c;保护代码安全是至关重要的。代码混淆是一种常用的技术&#xff0c;可以增加逆向工程的难度&#xff0c;防止他人对代码的篡改和盗用。本文将介绍如何实现iOS App代码混淆的步骤和操作方法。 整体流程 下面是实现iOS App代码混淆的整体流…

Python输入与输出

🥇作者简介:CSDN内容合伙人、新星计划第三季Python赛道Top1 🔥本文已收录于Python系列专栏: 零基础学Python 💬订阅专栏后可私信博主进入Python学习交流群,进群可领取Python视频教程以及Python相关电子书合集 私信未回可以加V:hacker0327 备注零基础学Python 订阅专…

浏览器渲染原理-解释回流重绘以及为什么transform效率高

浏览器是如何渲染页面 当浏览器的网络线程收到 HTML 文档后&#xff0c;会产生一个渲染任务&#xff0c;并将其传递给渲染主线程的消息队列。在事件循环机制的作用下&#xff0c;渲染主线程取出消息队列中的渲染任务&#xff0c;开启染流程。 整个渲染流程分为多个阶段&#xf…

HW面试经验分享 | 某服蓝队初级

前言 依稀记得是22年 7、8月份参加的HW&#xff0c;当时是比较炎热的时候&#xff0c;但又夹杂一丝秋意。也是头一次去离家乡比较远的地方&#xff0c;多少有点忐忑……&#xff08;怕被噶腰子、水土不服、吃穿用住没着落等等&#xff09;&#xff0c;但最终也是平安无事且顺利…

笔记84:关于递归法的一些感悟

题目1&#xff1a;二叉树的前序遍历 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(…

独立服务器如何安装Webmin面板

本周有一个客户&#xff0c;购买Hostease的独立服务器&#xff0c;询问我们的在线客服&#xff0c;独立服务器支持安装Webmin及如何安装的问题。我们为用户提供教程&#xff0c;用户很快完成了设置。在此&#xff0c;我们分享这个操作教程&#xff0c;希望可以对您有帮助。 Web…

SkyWalking 为所有的API接口增加 tag

背景胡扯 线上接口报错&#xff0c;接着被 SkyWalking 抓到&#xff0c;然后 SkyWalking 触发告警&#xff0c;最后老板你&#xff0c;让你辛苦一下&#xff0c;在明早上班前把这个bug 改了&#xff0c;并告诉你你是全公司的希望。谁说不是呢&#xff1f;为公司业务保驾护航&a…