我已在此处查看了所有帖子,但到目前为止找不到我的解决方案。 我确实设置了一个小服务,只应该监视我想要监视的其他服务是否运行,如果没有,请再次启动它并在应用程序事件日志中发送消息。
服务本身效果很好,没有什么特别的:),但是当我启动服务时,它使用大约1.6MB的RAM,并且每10秒就会增长到60-70k,这是很容易接受的。 我试过处理并清除所有资源。尝试使用System.Timers而不是实际的解决方案,但没有真正按照我的意愿工作,内存仍在增长。
调试版或发布版没有区别,我在.Net 2上使用它,不知道它是否会对你产生影响3,3.5或4。
任何提示?!
using System;
using System.IO;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
using System.Timers;
namespace Watchguard
{
class WindowsService : ServiceBase
{
Thread mWorker;
AutoResetEvent mStop = new AutoResetEvent(false);
/// <summary>
/// Public Constructor for WindowsService.
/// - Put all of your Initialization code here.
/// </summary>
public WindowsService()
{
this.ServiceName = "Informer Watchguard";
this.EventLog.Source = "Informer Watchguard";
this.EventLog.Log = "Application";
// These Flags set whether or not to handle that specific
// type of event. Set to true if you need it, false otherwise.
this.CanHandlePowerEvent = false;
this.CanHandleSessionChangeEvent = false;
this.CanPauseAndContinue = false;
this.CanShutdown = false;
this.CanStop = true;
if (!EventLog.SourceExists("Informer Watchguard"))
EventLog.CreateEventSource("Informer Watchguard", "Application");
}
/// <summary>
/// The Main Thread: This is where your Service is Run.
/// </summary>
static void Main()
{
ServiceBase.Run(new WindowsService());
}
/// <summary>
/// Dispose of objects that need it here.
/// </summary>
/// <param name="disposing">Whether or not disposing is going on.</param>
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
/// <summary>
/// OnStart: Put startup code here
/// - Start threads, get inital data, etc.
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args)
{
base.OnStart(args);
MyLogEvent("Init");
mWorker = new Thread(WatchServices);
mWorker.Start();
}
/// <summary>
/// OnStop: Put your stop code here
/// - Stop threads, set final data, etc.
/// </summary>
protected override void OnStop()
{
mStop.Set();
mWorker.Join();
base.OnStop();
}
/// <summary>
/// OnSessionChange(): To handle a change event from a Terminal Server session.
/// Useful if you need to determine when a user logs in remotely or logs off,
/// or when someone logs into the console.
/// </summary>
/// <param name="changeDescription"></param>
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
base.OnSessionChange(changeDescription);
}
private void WatchServices()
{
string scName = "";
ServiceController[] scServices;
scServices = ServiceController.GetServices();
for (; ; )
{
// Run this code once every 10 seconds or stop right away if the service is stopped
if (mStop.WaitOne(10000)) return;
// Do work...
foreach (ServiceController scTemp in scServices)
{
scName = scTemp.ServiceName.ToString().ToLower();
if (scName == "InformerWatchguard") scName = ""; // don't do it for yourself
if (scName.Length > 8) scName = scName.Substring(0, 8);
if (scName == "informer")
{
ServiceController sc = new ServiceController(scTemp.ServiceName.ToString());
if (sc.Status == ServiceControllerStatus.Stopped)
{
sc.Start();
MyLogEvent("Found service " + scTemp.ServiceName.ToString() + " which has status: " + sc.Status + "\nRestarting Service...");
}
sc.Dispose();
sc = null;
}
}
}
}
private static void MyLogEvent(String Message)
{
// Create an eEventLog instance and assign its source.
EventLog myLog = new EventLog();
myLog.Source = "Informer Watchguard";
// Write an informational entry to the event log.
myLog.WriteEntry(Message);
}
}
}
答案 0 :(得分:1)
至少,您需要在日志记录代码中执行此操作,因为EventLog
需要Dispose()
d。似乎这个资源可以在每次调用时重复使用而不是new
。您还可以在主循环中考虑using
对象ServiceController
,以使您的代码更加安全。
private static void MyLogEvent(String Message)
{
// Create an eEventLog instance and assign its source.
using (EventLog myLog = new EventLog())
{
myLog.Source = "Informer Watchguard";
// Write an informational entry to the event log.
myLog.WriteEntry(Message);
}
}
答案 1 :(得分:1)
您的代码可能会在循环内抛出异常,但不会捕获这些异常。因此,请按如下所示更改代码以捕获异常:
if (scName == "informer")
{
try {
using(ServiceController sc = new ServiceController(scTemp.ServiceName.ToString())) {
if (sc.Status == ServiceControllerStatus.Stopped)
{
sc.Start();
MyLogEvent("Found service " + scTemp.ServiceName.ToString() + " which has status: " + sc.Status + "\nRestarting Service...");
}
}
} catch {
// Write debug log here
}
}
你可以在调查之后删除外部的try / catch,留下using
语句以确保Dispose在被调用的情况下被调用。
答案 2 :(得分:0)
这应该移到循环中,因为您不希望在服务的整个过程中保留对旧服务句柄的引用:
ServiceController[] scServices = ServiceController.GetServices();
您还希望处理对EventLog
和ServiceController
实例的引用。正如Artem所指出的那样,要注意阻止你这样做的例外情况。
由于内存每10秒钟就会上升,所以它必须在你的循环中。
如果内存上升,无论你是否写入EventLog,那么这不是主要问题。
使用的内存是否会降低?即一段时间后垃圾收集器开始了吗?您可以在回到睡眠状态之前执行GC.Collect()
来测试GC的效果(尽管我会小心在生产中使用它)。
答案 3 :(得分:0)
我不确定我是否完全理解这个问题。您要监控的服务是否始终相同。从您的代码中可以看出答案是肯定的,如果是这种情况,那么您可以简单地创建ServiceController类实例,将服务名称传递给构造函数。 在你的线程例程中,你想继续循环,直到发出一个停止,并且WaitOne方法调用返回一个布尔值,所以while循环似乎是合适的。在while循环中,您可以在ServiceController类实例上调用Refresh方法以获取服务的当前状态。 事件记录应该简单地要求调用一个静态方法EventLog.WriteEntry方法,至少传递你的消息和源'Informer Watchguard' 当您从线程例程中的循环退出时,可以处理ServiceController实例 所有这些都意味着您创建的对象需要更少,因此不太可能存在某些资源泄漏。
答案 4 :(得分:0)
感谢所有建议。 最后,服务现在稳定了一些修改。
@Steve:我看到很多服务都以同名“Informer ......”开头,但我不知道全名,这就是我这样做的原因。