Мне нужна помощь, поскольку я заметил, что селен chromeDriver в С# не освобождает память должным образом. Я использую RamMap для отслеживания использования памяти. Если не выполнять следующие сценарии, использование памяти не увеличивается постоянно.
Запуск приведенных ниже сценариев в планировщике задач приводит к увеличению памяти в записи RamMap «Unused-Active» при каждом запуске. Я подтвердил, что в мониторе ресурсов, диспетчере задач или RamMap нет активных chromedriver или процессов chrome. Selenium.WebDriver v4.23.0. Chrome и ChromeDriver v127.
Скриншоты RamMap для справки: видно, что запись «Unused-Active» значительно увеличивается примерно через 5 минут запуска сценариев. Это значение не увеличивается, когда сценарии не выполняются.
Основная проблема, как показано на скриншотах, заключается в том, что «Неиспользуемый — Активный» увеличивается с 7000 КБ до 50 000 КБ за 5 минут. В течение 24 часов, если так будет продолжаться, это увеличение составит почти 1 238 4000 КБ или около 12 ГБ. Это вызывает серьезную проблему с производительностью, поскольку после недели работы машина использует более 80% оперативной памяти, которая просто не используется, но все еще считается «активной».
До запуска скриптов (После перезагрузки) - Значение не увеличивается:
10 минут простоя - скрипты не выполняются
15 запланированных задач, запускающих консольное приложение каждую минуту в течение 5 минут. Ценность значительно возросла.
10 минут простоя - остановить запуск скриптов
Воспроизводимый код, который я пробовал: (Создайте консольное приложение C# и настройте проект для запуска 15 запланированных задач в планировщике задач каждую минуту.)
using OpenQA.Selenium.Chrome;
namespace ChromeBotTest
{
public class Program
{
private static async Task Main(string[] args)
{
using (ChromeDriver? chromeDriver = new()) //using statement for automatic disposal
{
await Task.Delay(3000); //allow chrome to open for some short time
chromeDriver.Close(); //close all windows
chromeDriver.Quit(); //quit to fully close browser and release resources
}
}
}
}
using OpenQA.Selenium.Chrome;
namespace ChromeBotTest
{
public class Program
{
private static async Task Main(string[] args)
{
using (ChromeDriver? chromeDriver = new()) //using statement for automatic disposal
{
await Task.Delay(3000); //allow chrome to open for some short time
chromeDriver.Quit(); //quit to fully close browser and release resources
}
}
}
}
using OpenQA.Selenium.Chrome;
namespace ChromeBotTest
{
public class Program
{
private static async Task Main(string[] args)
{
ChromeDriver chromeDriver = new();
await Task.Delay(3000); //allow chrome to open for some short time
chromeDriver.Quit(); //quit to fully close browser and release resources
}
}
}
using OpenQA.Selenium.Chrome;
namespace ChromeBotTest
{
public class Program
{
private static async Task Main(string[] args)
{
ChromeDriver? chromeDriver = new();
await Task.Delay(3000); //allow chrome to open for some short time
chromeDriver.Close(); //close all windows
chromeDriver.Quit(); //quit to fully close browser and release resources
chromeDriver?.Dispose(); //dispose incase chromeDriver is not properly disposed
chromeDriver = null; //set to null to ensure its cleared
}
}
}
using OpenQA.Selenium.Chrome;
namespace ChromeBotTest
{
public class Program
{
private static async Task Main(string[] args)
{
ChromeDriver? chromeDriver = new();
await Task.Delay(3000); //allow chrome to open for some short time
chromeDriver.Close(); //close all windows
chromeDriver.Quit(); //quit to fully close browser and release resources
chromeDriver?.Dispose(); //dispose incase chromeDriver is not properly disposed
chromeDriver = null; //set to null to ensure its cleared
await Task.Delay(2000); //allow 2 second delay
GC.Collect();
GC.WaitForPendingFinalizers(); //clean up garabage collection
GC.Collect();
await Task.Delay(10000); //wait 10 seconds to allow garbage collection sufficent time to execute
}
}
}
Это не исправлено - обновлено начальное сообщение тестового кода.
Этот драйвер Chrome запускается в отдельном процессе? Или память увеличивается при повторном запуске процесса? Обычно я бы советовал использовать профилировщик памяти, но он в основном полезен для поиска управляемых утечек. Я подозреваю, что из-за этого происходит утечка неуправляемой памяти, и никакая сборка мусора не поможет. Но мне непонятно, в чем проблема, если ты распоряжаешься всем, что создал, то твои обязанности должны быть выполнены.
Если это не вызывает проблем с производительностью, я не уверен, что вам нужно решить проблему. .NET Framework не освобождает память только потому, что работает сборщик мусора. Среда выполнения сохранит выделенную память, поэтому операционная система по-прежнему будет видеть, что эта память используется (хотя она может считаться неактивной). Только если в системе закончится неиспользуемая память, среда выполнения .NET начнет отказываться от неиспользуемой памяти. Это ожидаемое поведение, если я правильно помню.
Некоторые дополнительные ресурсы:
Честно говоря, цифры, которые вы выделили на скриншотах, не сильно отличаются, если я чего-то не упускаю...
переход от 7000 КБ до 50 000 КБ за 5 минут — это большая разница. Если так будет продолжаться в течение 24 часов, это увеличение составит почти 12384000 КБ или около 12 ГБ. Это вызывает серьезную проблему с производительностью, поскольку после недели работы машина использует более 80% оперативной памяти, которая просто не используется, но все еще считается «активной». Обычно я перезагружаю компьютер, когда он достигает 85%, поскольку другие процессы, такие как IIS, начинают замедляться.
ключ в том, «если так будет продолжаться»... вполне нормально, что в какой-то момент оно достигает своего рода плато и выравнивается. Вы хотите использовать память, поскольку это будет быстрее, чем подкачка на диск. Если со временем он никогда не перестанет расти или начнет замедлять работу, потому что начинает выполнять подкачку на диск, вы можете рассмотреть возможность установки большего количества оперативной памяти. Браузеры также потребляют ресурсы, когда дело доходит до потоков/процессов, поскольку современные браузеры разделяют все домены на разные процессы, поэтому это также может быть количество процессов, которые замедляют работу, поглощая временные интервалы.
Вы также можете проверить диспетчер задач на наличие потерянных процессов chromedriver.exe. Маловероятно, что это является причиной высокого использования памяти, но проверить стоит. (chromedriver в какой-то момент обязательно выйдет из строя, и не всегда изящно)
Спасибо за вклад @browsermator. Я подтвердил, что нет зависших/потерянных процессов chromedriver.exe или chrome.exe. Эта машина, показанная на скриншотах, имеет 96 ГБ оперативной памяти. В целях тестирования я проводил тесты на этой машине, но наша производственная машина имеет 144 ГБ ОЗУ, поэтому возникает та же проблема. У нас есть несколько других сценариев, которые запускаются автоматически с использованием .NET и не вызывают такого потребления ресурсов. Мы уже видели, как эта запись в RamMap превысила 90 ГБ.
@freyfrey01, это подозрительно. Мы запускаем наши тесты на Windows Server (что-то недавнее) и запускаем тесты в ночное время. У нас на этом сервере 16 ГБ ОЗУ, и он отлично справляется с 12-часовым тестовым запуском. Но мы проводим тесты партиями. Мы не проводим 4000 тестов на селен подряд. Тесты на селене мобилизуют множество машин. Возможно, вам просто нужно периодически убивать процессы.
вы можете проверить/обновить драйверы видеокарты... Я видел, что это упоминалось как причина этого, когда я гуглил. (rammap не знает, что использует эту память, поэтому она указана как «неиспользуемая»)
Единственное, о чем я могу думать, это диспетчер драйверов, потому что он выполняет некоторые операции по загрузке файлов ввода-вывода. (от таких вещей вы бы хотели избавиться, так что, возможно, они делают это неправильно). Вы можете попробовать явно указать пути к chromedriver и options.setBinary (путь к браузеру), чтобы исключить это.
Спасибо за комментарии @browsermator, я подтвердил, что это не драйверы видеокарты, используя приложение Microsoft Process Explorer, которое показывает использование оперативной памяти драйвера (упоминается на других форумах). Я также протестировал параметр setBinary (кажется, устаревший для options.BinaryLocation=...) options.BinaryLocation = @"C:\Program Files\Google\Chrome\Application\chrome.exe"; ChromeDriver chromeDriver = новый (варианты); который дал те же результаты
Я полагаю, что, возможно, стоит попробовать Geckodriver/Firefox, чтобы исключить какую-то ошибку в chromedriver. Если вы наберете IWebDriver, вы можете использовать тот же код, но для инициализации.
@browsermator попробовал использовать драйвер Firefox и получил те же результаты. Кто-нибудь способен воспроизвести?
Я думаю, что это, вероятно, исключает сторону Selenium. (но обязательно избавьтесь от всех вызовов обработки GC и удаления... пусть GC сделает это автоматически) Запуск 15 экземпляров ядра .NET + Selenium + веб-драйвера + браузера за одну минуту кажется многоватым. Запустите 1 экземпляр и убедитесь, что он корректно завершает работу через несколько минут. (вызывается команда выхода?) Поскольку ядро .NET является собственной средой выполнения, возможно, в Rammap его ресурсы указаны как неиспользуемые.
может ли это быть так просто? Нет выхода()?
Отследил его до Trellix/Mcafee, удерживающих зомбированные дескрипторы завершенных процессов с помощью RamMap и https://github.com/randomascii/blogstuff/tree/main/FindZombieHandles
просто используйте driver.quit()... пусть GC выполнит свою работу автоматически. Сначала вам не нужен .close() (в основном для закрытия одной вкладки, если у вас их несколько), не нужно удалять или использовать с помощью... не нужно вручную использовать GC. Я бы сравнил ваши результаты с ручным запуском и закрытием браузера (подозреваю, что это все связано с браузером). Единственное отличие от сеанса Selenium по умолчанию заключается в том, что временные каталоги/профили/файлы создаются и затем очищаются при выходе. Логика GC браузера довольно сложна, и трудно предсказать, когда она будет иметь дело с вещами, помеченными для удаления.