文档章节

一个C#语言编写Windows服务的例子:强制杀死高内存占用的进程

北风其凉
 北风其凉
发布于 2016/08/07 15:35
字数 1025
阅读 1365
收藏 34

先说说我遇到的问题,有一台电脑不知道发了什么疯,在开机40-50分钟后会变得非常卡。我打开资源监视器看了下,原来是一个名为scvhost.exe的进程作怪,将这个进程结束掉(事实上Windows会重启这个进程),电脑就又会恢复正常了。

产生这个问题的具体原因现在还没有找到,不过我却想了一个治标的办法,就是写一个Windows服务监视系统内的进程内存占用情况,在剩余可用内存小于15%时,如发现有进程的内存占用超过总内存的45%(也可以是30%或其他数字),则杀死此进程。

我使用的操作系统为Win7旗舰版,VisualStudio版本为2012。

新建项目,找到VisualC#下的Windows服务,建立一个Windows服务项目:

关于建立Windows服务项目,我参考了这篇博客:http://yqin.iteye.com/blog/509583

我建立的项目结构如下:

ServiceMain.cs,为项目自动创建的cs文件(原名为Service1,我改名为ServiceMain),ServiceMain类继承自ServiceBase

1、CanPauseAndContinue设置为True

2、CanShutdown设置为True

3、ServiceName设置为ProcessMonitor

4、在设计器界面单击鼠标右键,点击“添加安装程序”,生成ProjectInstall.cs

ProjectInstall.cs,ProjectInstall类继承自System.Configuration.Install.Installer,其中:

System.ServiceProcess.ServiceInstaller类实例serviceInstaller

1、Description设置为“进程杀手”

2、DisplayName设置为ProcessMonitor

3、StartType设置为Automatic(包括自动、手动、禁用,这里选择自动)

System.ServiceProcess.ServiceProcessInstaller类实例serviceProcessInstaller

1、Account设置为LocalSystem(指定运行此服务的用户类型)

下面开始写代码,在ServiceMain.cs中添加如下代码:

using Microsoft.VisualBasic.Devices;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;

namespace ProcessMonitor
{
    public partial class ServiceMain : ServiceBase
    {
        /// <summary>
        /// 进程监测计时器
        /// </summary>
        System.Timers.Timer timerScanner = new System.Timers.Timer();
        LinkedList<int> lstProc = new LinkedList<int>();
        /// <summary>
        /// 剩余内存小于此百分比时才会杀死高内存占用进程
        /// </summary>
        private double PERCENT_AT = 0.15;
        /// <summary>
        /// 杀死内存占用百分比高于此数值的进程
        /// </summary>
        private double PERCENT_PT = 0.45;

        public ServiceMain()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            base.OnStart(args);
            EventLog.WriteEntry("PROCESS MONITOR: START");
            timerScanner.Enabled = true;
            timerScanner.Elapsed += timerScanner_Tick;
            timerScanner.Interval = 10000;
            timerScanner.Start();
        }

        protected override void OnPause()
        {
            EventLog.WriteEntry("PROCESS MONITOR: PAUSE");
            base.OnPause();
        }

        protected override void OnContinue()
        {
            base.OnContinue();
            EventLog.WriteEntry("PROCESS MONITOR: CONTINUE");
        }

        protected override void OnStop()
        {
            EventLog.WriteEntry("PROCESS MONITOR: STOP");
            base.OnStop();
        }

        private void timerScanner_Tick(object sender, EventArgs e)
        {
            try
            {
                EventLog.WriteEntry("PROCESS MONITOR: CHECK PROCESSES...");
                ComputerInfo cInfo = new ComputerInfo();
                long totalPhyMem = Convert.ToInt64(cInfo.TotalPhysicalMemory);
                long availablePhyMem = Convert.ToInt64(cInfo.AvailablePhysicalMemory);
                double percentATMem = availablePhyMem * 1.0 / totalPhyMem;
                if (percentATMem < PERCENT_AT)
                {
                    foreach (Process proc in Process.GetProcesses())
                    {
                        long procMem = proc.WorkingSet64;
                        double percentPTMem = procMem * 1.0 / totalPhyMem;
                        if (percentPTMem > PERCENT_PT && !lstProc.Contains(proc.Id))
                        {
                            EventLog.WriteEntry("PROCESS MONITOR: KILL PROCESS " + proc.ProcessName);
                            proc.Kill();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                EventLog.WriteEntry(ex.Message, EventLogEntryType.Error);
            }
        }
    }
}

关于这段代码,有以下几点说明:

1、需要手动添加引用Microsoft.VisualBasic,支持对命名空间Microsoft.VisualBasic.Devices的引用。

2、Timer千万不要从可视化编辑器的组件库中拖入,因为Windows服务不支持System.Windows.Forms.Timer,我们使用的Timer是System.Timers.Timer。

3、不要在代码中使用诸如MessageBox之类的UI,写日志可以使用EventLog,记录下的日志可以在Windows事件查看器中查到。

有关EventLog的使用说明,可参考相关MSDN页面:

https://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog(VS.71).aspx

代码编写完毕后,生成解决方案,此时可在Debug目录中找到编译好的ProcessMonitor.exe。

安装服务可以通过VS提供的InstallUtil工具实现,用管理员身份打开VS开发人员命令提示,输入命令:

InstallUtil ProcessMonitor.exe所在绝对路径

安装完毕后,就可以在Windows的服务列表中找到此服务了

启动该服务后,ProcessMonitor就可以正式开始工作了!

我们可在事件查看器中找到EventLog打印的相关日志:

如果需要卸载此服务,在安装命令的基础上,添加一个命令行参数/u即可:

InstallUtil /u ProcessMonitor.exe所在绝对路径

这些内容都会被同时写入ProcessMonitor.exe同目录下的日志文件ProcessMonitor.InstallLog中。

附:本程序的工程文件可在此地址下载:http://pan.baidu.com/s/1kVCV0ov

END

© 著作权归作者所有

北风其凉

北风其凉

粉丝 120
博文 497
码字总数 462305
作品 4
朝阳
程序员
私信 提问
加载中

评论(3)

暮雨晨烟
暮雨晨烟
结果svchost抢不到CPU,但你的服务抢了更多CPU,
Angel  〆 秋之泪
Angel 〆 秋之泪
新手表示看不懂
酸奶瓶盖儿
酸奶瓶盖儿
领教了!
Android安全模型之Android安全机制(内存管理)

Ashmem匿名共享内存 Android的匿名共享内存(Ashmem)机制基于Linux内核的共享内存,但是Ashmem与cache shrinker关联起来,增加了内存回收算法的注册接口,因此Linux内存管理系统将不再使用内...

柳哥
2014/12/02
692
0
Python爬虫 监控进程

一:前言 python 语言具有良好的垃圾回收功能,但是实际运用爬虫的时候还是会出现内存逐渐增大的现象,包括数据库服务占用的内存也会不断增加。这样服务器或者电脑就会收到一定的影响。这次的...

布咯咯_rieuse
2017/11/25
0
0
Linux系统管理---进程管理(查看进程、终止进程、更改进程优先级)

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/twilight_karl/article/details/77587740 查看进程 ps ps aux 查看所有进程,使用BSD操作系统格式 ps -le 查看系统所...

twilight0402
01/05
0
0
C#性能理解以及CTS

关于C#/.NET性能 在上次的例子里面,第二次执行Console.WriteLine()方法时,会完全跳过JITCompiler编译。因为第一次已经完全编译为了本地CPU指令并且返回了指令在内容里的入口地址,所以这一...

mszhangxuefei
2012/07/10
0
0
详细讲解:关于Linux操作系统的进程管理

1、程序和进程 程序是为了完成某种任务而设计的软件,比如OpenOffice是程序。什么是进程呢?进程就是运行中的程序。 一个运行着的程序,可能有多个进程。 比如 LinuxSir.Org 所用的WWW服务器...

JavaGG
2009/05/08
367
0

没有更多内容

加载失败,请刷新页面

加载更多

vue入门--简单路由配置

本文转载于:专业的前端网站➜vue入门--简单路由配置   在初始化vue init webpack <工程名>时,有一步是询问是否安装vue-router,选择yes,如果没有安装的话,后面需要自己安装。然后在目录...

前端老手
27分钟前
3
0
怎么给视频配音

很多刚开始尝试视频制作的小伙伴,帮助到怎么给制作完成的视频配音,其实给视频配音的方法非常简单,在手机上可以进行制作,下面一起来看看给视频配音的方法吧! 具体步骤如下: 1、首先在手...

白米稀饭2019
36分钟前
3
0
windows批处理bat脚本编写

什么是bat脚本 .bat结尾的文件其实就是windows上的批处理脚本,Windows中的bat文件相当于 Linux中shell编程的.sh脚本,批量执行DOS命令。 其最简单的例子,是逐行书写在命令行中会用到的各种...

孙幼凌
44分钟前
3
0
华为手机翻译功能怎么使用?这三种方法请务必收藏

华为手机翻译功能怎么使用?在我们的生活中会经常遇到翻译问题,许多外语不好的朋友该怎么办呢?华为手机已经为我们解决了这个问题,今天小编就教大家学会使用华为手机中的三种翻译技巧,需要...

翻译小天才
52分钟前
5
0
企业服务软件开发中需要注意的三个问题

在开发企业服务软件时,我们需要分为:业务需求、用户需求、产品需求,三大需求层次,三个层次互相关联,企业服务软件开发首先要服务业务,需要满足业务的需求,再关注用户体验,也就是用户需...

积木创意科技
55分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部