我们有一个用.Net 3.5编写的服务器组件。它作为Windows Server 2008 Standard Edition上的服务运行。它运作良好,但经过一段时间(天),我们注意到大幅减速和增加工作量。我们期望某种内存泄漏并使用WinDBG / SOS来分析进程的转储。不幸的是,GC Heap没有显示任何泄漏,但我们注意到JIT代码堆在启动后从8MB增长到几天后超过1GB。
我们自己不使用任何动态代码生成技术。我们使用以动态代码生成而闻名的Linq2SQL,但我们不知道它是否会导致这样的问题。
主要问题是,是否有任何技术来分析转储并检查WinDBG转储中显示的所有主机代码堆块来自何处?
[更新]
与此同时,我们进行了更多分析,并将Linq2SQL视为可能的嫌疑,特别是因为我们不使用预编译查询。以下示例程序创建了完全相同的行为,其中随着时间的推移创建了越来越多的主机代码块。
using System;
using System.Linq;
using System.Threading;
namespace LinqStressTest
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 100; ++ i)
ThreadPool.QueueUserWorkItem(Worker);
while(runs < 1000000)
{
Thread.Sleep(5000);
}
}
static void Worker(object state)
{
for (int i = 0; i < 50; ++i)
{
using (var ctx = new DataClasses1DataContext())
{
long id = rnd.Next();
var x = ctx.AccountNucleusInfos.Where(an => an.Account.SimPlayers.First().Id == id).SingleOrDefault();
}
}
var localruns = Interlocked.Add(ref runs, 1);
System.Console.WriteLine("Action: " + localruns);
ThreadPool.QueueUserWorkItem(Worker);
}
static Random rnd = new Random();
static long runs = 0;
}
}
当我们用预编译的Linq查询替换Linq查询时,问题似乎消失了。
答案 0 :(得分:1)
使用'singleton'DataContext
,而不是在循环中一直重新创建它。
我确信效果与编译的查询相同。
<强>更新强>
这个问题在.NET 4中被“纠正”,因为它支持GC'able动态程序集。
答案 1 :(得分:0)
我知道.net中内存泄漏的唯一方法是由于事件处理,请查看: