Profiler报告ServiceBase.Run导致高CPU使用率

时间:2014-09-15 00:16:22

标签: .net service

我在.NET中开发了一个相当复杂的Windows服务(在2.0 CLR上运行),我注意到它消耗了大量的CPU周期,有效地最大化了一台机器的核心。

我附加了一个分析器(SlimTune),它报告了超过90%的CPU周期花费在ServiceBase.Run。我的服务似乎运行正常,它创建了大约9-15个其他线程,这些线程都在EventWaitHandle.WaitOneStread.Read调用中被阻止(按设计)并且运行正常,我在程序中没有循环导致CPU烧毁的代码,因此ServiceBase.Run会出现问题。

我看了一下反射器,我在Run方法调用树中看不到任何循环,我的服务的Start方法完成并将控制返回给它的调用者。

我的代码很简单,让它成为一个神秘的原因:

public static class Program {

    public const String ServiceName = "FooService";

    public static void Main(String[] args) {

        using(FooService service = new FooService()) {

            ServiceBase.Run( service );
        }
    }
}

public partial class FooService : ServiceBase {

    private FooServiceImplementation _fooService;

    public FooService() {

        this.ServiceName = "FooService";
    }

    protected override void Dispose(Boolean disposing) {
        base.Dispose( disposing );
        if( disposing ) {

            if( _fooService != null ) {
                _fooService.Dispose();
                _fooService = null;
            }
        }
    }

    protected override void OnStart(String[] args) {

        try {

            // Load configuration.
            LoadConfiguration();

            // DO NOT CALL Config.Trace before Config has loaded, because the ExceptionsPath isn't yet set.
            // TODO: Use the temp directory if ExceptionsPath is not set.
            if( Config.DebuggerBreakOnStart ) {

                Debugger.Break();
            }

            Config.Trace("[OnStart] LoadConfiguration() complete.");

            _fooService = new FooServiceLoop();

            Config.Trace("[OnStart] _fooService instantiated.");

            _fooService.Start();

            Config.Trace("[OnStart] _fooService.Start() complete.");

        } catch(Exception ex) {

            Config.LogException( ex );

            throw;
        }
    }

    // Other methods omitted for brevity

我的日志显示正在调用Config.Trace("[OnStart] _fooService.Start() complete.");并且正在返回OnStart方法。

1 个答案:

答案 0 :(得分:1)

ServiceBase.Run方法告诉系统启动所有ServiceBase派生的实例(或FooService,在您的情况下)。它通过设置一些结构然后调用本机StartServiceCtrlDispatcher函数来完成此操作。此函数进入处理服务控制消息的等待状态,并将其传递给ServiceBase派生的实例(如果适用)。这意味着因为ServiceBase.Run是第一个执行的方法,并且在完成和处理所有其他代码之前不会退出,它似乎是整个应用程序中运行时间最长的方法。这是用词不当,因为它大部分时间都处于等待状态而不使用CPU,等待服务控制请求。 SlimTune告诉你在方法中花费的时间(作为在线程中花费的时间的百分比,参见CHM文件中的QuickStart部分),这只是减去方法从它开始时退出的时间。这与使用的CPU周期不同。 90%这意味着您服务中的代码实际上只占总运行时间的10%。

除非您不立即从OnStart返回,否则在OnStop中花费大量时间,或花费大量时间处理其他服务控制请求ServiceBase.Run,在CPU周期方面没有太多使用。

注意:系统在ServiceBase退出ServiceBase.Run之前处理它们。因此,您不需要将ServiceBase派生的实例放在using语句中。我不认为这会给你带来任何问题;但这可能会导致ObjectDisposedException