Переполнение памяти программы - C#
Формулировка задачи:
Пишу программу для парсинга одного сайта. Сам сайт парсится с помощью CsQuery. Нужно за раз обработать нужный диапазон страниц сайта. Задаётся начальная и конечная ссылки для парсинга и программа в несколько потоков перебирает все страницы в диапазоне и извлекает нужную информацию в List, что бы после окончания сохранить всё в файл. Нужное количество потоков запускается, и они по очереди берут из счётчика текущей страницы свой номер и работают с ним. В потоках написан цикл While, что бы они не закрывались, пока не спарсили последнюю страницу. После окончания парсинга отдельно сохраняется вся информация в List. Но проблема в том, что парсится будут большие диапазоны страниц больше миллиона, а при тестовом запуске на диапазоне в 10 000 страниц программа начинает занимать в памяти больше 1,5 гигабайт. В отдельной программе пробовал заполнять List случайными данными, по типу тех, что должны были быть извлечены. Добавил 100 000 строк, и размер оперативной памяти, используемой программы не превышал 100 мегабайт. Парсинг так же работает правильно, никаких избыточных данных он не добавляет. Я грешу на мою неправильную работу с потоками, и то, что сборщик мусора не уничтожает данные с прошлых проходов парсинга. Пробовал разные способы так и не решил проблему с утечкой памяти. Помогите найти ошибку, или подсказать более правильный метод работы с потоками. Код прикладываю.
class Program { static int begin_of_post = 2950774; //начальный индекс постов static int end_of_post = 2951774; //конечный индекс static int current_post; //текущий пост для потоков static List<string> list_posts = new List<string>(); //список хранения данных о постах static void Main(string[] args) { ServicePointManager.DefaultConnectionLimit = 1000000000; // количество одновременных соединений current_post = begin_of_post; Thread my_tr; for (int i = 0; i < 10; i++) //запуск потоков { my_tr = new Thread(parse_site); my_tr.Start(); } Console.ReadLine(); save_to_file(); } static void parse_site() { while (current_post <= end_of_post) { int link_to_post =current_post; //ссылка на пост Interlocked.Increment(ref current_post); //инкремент счётчика CQ cq; try { cq = CQ.CreateFromUrl("http://site.ru/" + link_to_post); // загрузка кода страницы } catch { Console.WriteLine("Error " + link_to_post); continue; } string post_info; ... //сам парсинг сайта ... int current = int.Parse(link_to_post) - begin_of_post; int end = end_of_post - begin_of_post; Console.WriteLine("Обработана ссылка " + current.ToString() + " ИЗ " + end.ToString()); Thread my_tr_save=new Thread(save_post); my_tr_save.Start(post_info); } } static void save_post(object post_info) { ... // Парсинг информации о странице ... lock (list_posts) { list_posts.Add(post_info.ToString()); } } static void save_to_file() { ... //сохранение строк list_posts в файл ... } }
Решение задачи: «Переполнение памяти программы»
textual
Листинг программы
static void save_post(object post_info) { lock (list_posts) { list_posts.Add(post_info.ToString()); } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д