Проникновение кеша .NET JIT?
У нас есть серверный компонент, написанный на .Net 3.5. Он работает как служба на стандартной версии Windows Server 2008. Он отлично работает, но через некоторое время (дни) мы наблюдаем значительное замедление и увеличенный рабочий набор. Мы ожидали некоторую утечку памяти и использовали WinDBG/SOS для анализа дампов процесса. К сожалению, GC Heap не обнаруживает утечки, но мы заметили, что куча JIT-кода выросла с 8 МБ после старта до более чем 1 ГБ через несколько дней.
Мы не используем какие-либо методы генерации динамического кода самостоятельно. Мы используем 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 прекомпилированным, проблема, похоже, исчезает.
Ответы
Ответ 1
Используйте "singleton" DataContext
вместо того, чтобы воссоздавать его все время в цикле.
Я уверен, что эффект будет таким же, как скомпилированные запросы.
Update:
Эта проблема должна быть исправлена в .NET 4, поскольку она поддерживает динамические сборки GC'able.
Ответ 2
Единственный способ, которым я знаю утечку памяти в .net, связан с обработкой событий, проверьте это: