У нас есть серверный компонент, написанный на .Net 3.5. Он работает в качестве службы на Windows Server 2008 Standard Edition. Он отлично работает, но через некоторое время (дни) мы замечаем значительное замедление и увеличение рабочего набора. Мы ожидали утечку памяти и использовали WinDBG / SOS для анализа дампов процесса. К сожалению, кучи GC не показывает утечки, но мы заметили, что куча кода JIT выросла с 8 МБ после запуска до более 1 ГБ через несколько дней.
Мы не используем собственные методы динамического генерирования кода. Мы используем Linq2SQL, который известен динамической генерацией кода, но мы не знаем, может ли это вызвать такую проблему.
Главный вопрос: существует ли какой-либо метод для анализа дампа и проверки, откуда берутся все эти блоки кучи хост-кода, показанные в дампах WinDBG?
[Update]
Тем временем мы провели еще один анализ и в качестве вероятного подозрения использовали 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 на предварительно скомпилированный, проблема, похоже, исчезнет.