Я постоянно (каждые 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 байт).
В профилировщике памяти, когда я отслеживаю, что использует строковый объект, я вижу, что это в основном (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();
}
ImportFileJob
? Как это реализовано? - person Tigran   schedule 19.02.2012StringBuilder
излишне. Нет выгоды IOW. - person leppie   schedule 19.02.2012