Я постоянно (каждые 30-60 минут) получаю исключение System.OutOfMemoryException в моей службе Windows. Работа сервиса состоит в том, чтобы зациклить 6 каталогов, которые содержат файлы данных, которые сервисные данные моют в общий формат данных XML.
Эти 6 папок содержат 5-10 000 файлов в каждой, поэтому общее количество файлов составляет около 45 000, и новые файлы добавляются в течение дня. Там добавляется около 1-2000 новых файлов в день. Размер файлов составляет от 4 до 500 КБ.
Каждый файл данных стирается в общий формат данных XML через объект XElement.
Я использовал RedGates ANTS Memory Profiler в службе, и объекты, которые используют больше всего памяти, - это строка (около 90 000 000 байт) и XElement (около 51 000 000 байт).
В Memory Profiler, когда я отслеживаю, что использует строковый объект, я вижу, что это в основном (93%) объект XElement, который использует строковый объект.
Сервер имеет 6 процессоров и 6 ГБ оперативной памяти, поэтому я не понимаю, почему я получаю исключение OutOfMemoryException. Если я посмотрю на службу Windows в процессах, то ее МАКСИМАЛЬНОЕ использование ОЗУ составило 1,2 ГБ.
Я читал, что сборщик мусора в .NET не очищает строковый объект, потому что строковый объект хранится в внутренней таблице. Может ли это быть ошибкой, если да, что я могу с этим поделать?
Код ниже показывает, как я перебираю файлы. Как вы можете видеть, я также пытался взять 20 файлов одновременно. Это просто выдвигает OutOfMemoryException на несколько часов, поэтому служба будет работать в течение 4-5 часов вместо 30-60 минут.
Почему я могу использовать OutOfMemoryException?
private static void CheckExistingImportFiles(object sender, System.Timers.ElapsedEventArgs e)
{
CheckTimer.Stop();
var dir = Directory.GetFiles(RawDataDirectory.FullName, "*.*", SearchOption.AllDirectories);
List<ManualResetEvent> doneEvents = new List<ManualResetEvent>();
int i = 0;
//int doNumberOfFiles = 20;
foreach (string existingFile in Directory.GetFiles(RawDataDirectory.FullName, "*.*", SearchOption.AllDirectories))
{
if (existingFile.EndsWith("ignored") || existingFile.EndsWith("error") || existingFile.EndsWith("importing"))
{
//if (DateTime.UtcNow.Subtract(File.GetCreationTimeUtc(existingFile)).TotalDays > 5)
// File.Delete(existingFile);
//continue;
}
StringBuilder fullFileName = new StringBuilder().Append(existingFile);
if (!fullFileName.ToString().ToLower().EndsWith("error") && !fullFileName.ToString().ToLower().EndsWith("ignored") && !fullFileName.ToString().ToLower().EndsWith("importing"))
{
File.Move(fullFileName.ToString(), fullFileName + ".importing");
fullFileName = fullFileName.Append(".importing");
ImportFileJob newJob = new ImportFileJob(fullFileName.ToString());
doneEvents.Add(new ManualResetEvent(false));
ThreadPool.QueueUserWorkItem(newJob.Run, doneEvents.ElementAt(i));
i++;
}
//if (i > doNumberOfFiles)
//{
// i = 0;
// doNumberOfFiles = 20;
// break;
//}
}
i = 0;
WaitHandle.WaitAll(doneEvents.ToArray());
CheckTimer.Start();
}