Windows 7 上的 C# ServerManager 内存泄漏
C# ServerManager leaking memory on Windows 7
我一直在尝试诊断仅出现在 Windows 7/Server 2008 R2 上的服务中的内存泄漏。我将其缩小到我们使用 Microsoft.Web.Administration.ServerManager 收集有关我们站点中应用程序的信息的位置。我将其缩减为下面的控制台应用程序,它表现出相同的行为。它可能仍然比需要的更复杂,但我想尽可能多地模拟服务的行为。
我发现之前的一个问题 here 非常相似,并进行了答案中建议的更改。这似乎降低了增长率,但它仍然显着泄漏(在评论 "Original Test" 下我已经注释掉了我根据这些答案更改的代码。"Modified Test" 评论表明我所做的更改。我最初没有 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;
}
}
}
@Lex Li 的评论中提供了答案。
Move the check to a separate process. Calling IIS REST API, PowerShell, or even appcmd and parse the result. Let the leak be out of your own service.
我一直在尝试诊断仅出现在 Windows 7/Server 2008 R2 上的服务中的内存泄漏。我将其缩小到我们使用 Microsoft.Web.Administration.ServerManager 收集有关我们站点中应用程序的信息的位置。我将其缩减为下面的控制台应用程序,它表现出相同的行为。它可能仍然比需要的更复杂,但我想尽可能多地模拟服务的行为。
我发现之前的一个问题 here 非常相似,并进行了答案中建议的更改。这似乎降低了增长率,但它仍然显着泄漏(在评论 "Original Test" 下我已经注释掉了我根据这些答案更改的代码。"Modified Test" 评论表明我所做的更改。我最初没有 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;
}
}
}
@Lex Li 的评论中提供了答案。
Move the check to a separate process. Calling IIS REST API, PowerShell, or even appcmd and parse the result. Let the leak be out of your own service.