Нужен способ обойти ошибку "узел исчерпал память"
Я анализирую ~250K XML и загружаю данные в базу данных SQLite. Я использую версию узла 10.15.1 с cheerio
а также better-sqlite3
на ноутбуке Mac OS X с 8 ГБ памяти. я readdirSync
- целую папку с файлами ~ 250 КБ, анализ файлов XML и загрузку извлеченных данных с использованием транзакций в пакетах по 10 КБ. я использую --max_old_space_size=4096
но все еще получаю ФАТАЛЬНУЮ ОШИБКУ: неэффективные компактные метки вблизи предела кучи Выделение не удалось - кучи JavaScript не хватает памяти.
Теперь, если я обрабатываю файлы размером 100 КБ, затем выхожу из узла, затем снова запускаю и обрабатываю оставшиеся файлы ~150 КБ, тогда все работает. Но я бы предпочел сделать все это за один раз, поскольку это то, что нужно делать без присмотра. Есть ли что-нибудь еще, что я могу сделать, учитывая мои ограничения? Я не могу использовать машину с большим объемом памяти, потому что у меня нет доступа к ней. Я мог бы попытаться натолкнуть --max_old_space_size
немного больше, или я мог бы попытаться сделать меньшие пакеты транзакций, но я не уверен, поможет ли это (я пробовал с 8000 файлов на транзакцию вместо 10 КБ, но это слишком исчерпало память). Единственное, что сейчас помогает, это выход из узла между ними. Могу ли я имитировать это? То есть сказать узлу освободить всю память и сделать вид, что она была перезапущена? Есть еще мысли?
1 ответ
Итак, я, наконец, наткнулся на решение моей проблемы (я использую "спотыкаться", потому что я не уверен, что это определенно правильная стратегия, но она работает для меня).
Я обнаружил, что на самом деле увеличение --max_old_space_size
ценность на самом деле не помогла мне. В любом случае, как я уже упоминал выше, мой MacBook имеет только 8 ГБ, поэтому у меня все равно низкий лимит. Наоборот, что помогло, так это просто уменьшить размер моей партии. Таким образом, вместо обработки 10K XML, хранения их данных в памяти, а затем вставки их в транзакцию в SQLite, я обрабатывал 1K XML за раз. Конечно, для обработки ~250К файлов мне пришлось иметь дело с 250 циклами вместо 25 циклов, но это не слишком увеличивало мое время. Я обнаружил, что время обработки довольно линейное, около 5K мс на 1K файлов (или 50K мс на 10K файлов). SQLite работает довольно быстро, независимо от того, добавляю я 1K или 10K INSERT в транзакцию, но это мой процесс парсера XML, который начинает работать при работе с очень большими объемами данных. На самом деле, это также не может быть проблемой с cheerio
(что я нашел очень хорошим). Это может быть мой стиль кодирования, который можно значительно улучшить.
В любом случае обработка 1К транзакций с --max_old_space_size=2048
сделал работу за меня. Использование памяти узлом (как показано в Activity Monitor было довольно стабильным, и весь дамп файлов размером 250 КБ был проанализирован и загружен в БД примерно за 42 минуты. Я могу с этим смириться.