首页 > 解决方案 > C# ServerManager 在 Windows 7 上泄漏内存

问题描述

我一直在尝试诊断仅出现在 Windows 7/Server 2008 R2 上的服务中的内存泄漏。我将范围缩小到我们使用 Microsoft.Web.Administration.ServerManager 收集有关我们网站中应用程序的信息的地方。我将它缩减到下面的控制台应用程序,它表现出相同的行为。它可能仍然比它需要的更复杂,但我想尽可能地模拟服务的行为。

我在这里找到了一个非常相似的先前问题,并在答案中提出了建议的更改。这似乎降低了增长率,但它仍然显着泄漏(在“原始测试”评论下,我已经注释掉了我根据这些答案更改的代码。“修改后的测试”评论表明我所做的更改。我没有t 最初有 GC.Collect 调用,当我在 Windows 10 系统上运行它时,它在垃圾收集开始之前增长了相当长的一段时间。有了 GC.Collect 调用,它在 Win 10 上运行而没有增长,但在 Win 7 上没有任何区别。

我在一个分析器下运行它,该分析器表明泄漏的内存是本机的,并且泄漏来自 nativerd.dll。

有没有人遇到过这样的问题?我是 C# 新手,仍在学习垃圾收集的工作原理,所以我想知道我做错了什么?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Web.Administration;

namespace ServerManagerLeakTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Working.");
            var me = new MyClass();
            me.Run();
        }
    }

    internal class MyClass
    {
        ServerManagerWrapper _smw = new ServerManagerWrapper();

        public void Run()
        {
            while (true)
            {
                var t = Task.Run(async delegate
                {
                    DoWork();
                    await Task.Delay(1000);
                });
                try
                {
                    t.Wait();
                }
                catch (Exception e)
                {
                    Console.Write("Main Exception: " + e.Message);
                }
                Console.Write(".");
            }
        }
        public void DoWork()
        {
            try
            {
                var data = _smw.GetWebApps().ToList();
                data.Clear();
            }
            catch (Exception e)
            {
                Console.Write("DoWork Exception: " + e.Message);
            }
        }
    }

    internal class ServerManagerWrapper
    {
        public List<int> GetWebApps()
        {
            List<int> result = new List<int>() { };

            // Original Test
            //
            // using (var serverManager = new ServerManager())
            // {
            //     foreach (var site in serverManager.Sites)
            //     {
            //         result.AddRange(GetWebApps(site));
            //    }
            //}

            // Modified Test
            var serverManager = new ServerManager();
            foreach (var site in serverManager.Sites)
            {
                result.AddRange(GetWebApps(site));
            }
            serverManager.Dispose();
            serverManager = null;
            System.GC.Collect();

            return result;
        }

        private IEnumerable<int> GetWebApps(Site site)
        {
            // Original Test
            //
            //for (var application in site.Applications)
            //{
            //    yield return application.GetHashCode();
            //}

            // Modified Test
            List<int> result = new List<int>() { };
            for (int i = 0; i < site.Applications.Count; i++)
            {
                result.Add(site.Applications[i].GetHashCode());
            }

            return result;
        }
    }
}

标签: c#memory-leakswindows-7-x64

解决方案


@Lex Li 的评论中提供了答案。

将支票移至单独的进程。调用 IIS REST API、PowerShell 甚至 appcmd 并解析结果。让泄漏不再是您自己的服务。


推荐阅读