У меня есть 100% воспроизводимое OutOfMemoryError
(чаще всего из-за превышения лимита накладных расходов GC) при запуске моего приложения Spark. Это происходит примерно на 700-м этапе.
Поскольку стек ошибок всегда включает такие классы, как .ui.
, TaskSchedulerImpl
и т. д., я пришел к выводу, что проблема заключается не в исполнителях, а в самом процессе-драйвере. Этот вывод подтверждается следующим наблюдением: за несколько минут до OOM вывод stdout
начинает приостанавливаться на секунду или около того, печатая множество строк сразу после паузы.
spark.driver.memory
настроен на 10 ГБ, но используемые инструменты отладки показывают, что драйвер использует только 1 ГБ:
- I've used these great instructions on collecting GC statistics and analyzing it with the gceasy.io service; it clearly showed that:
- The maximum heap usage after GC is approximately 1Gb.
- Ближе к моменту OOM график «использования кучи» почти достигает максимума в 1Gb, и многочисленные события GC не влияют на это.
GC overhead limit exceeded
в лучшем виде.
- I've used the MAT to analyse the heap dump created immediately after the OutOfMemoryError.
- The heap dump contains approximately the same 1Gb of data.
- Дерево доминаторов показывает, что более половины его потребляется объектами пользовательского интерфейса.
Этот вопрос ответ предполагает, что библиотеки JNI могут использовать 10Gb-1Gb=9Gb; но, по-видимому, Spark не использует это в своей основе; я тоже.
Я использовал ответ на этот вопрос, чтобы свести к минимуму сохраняемые данные пользовательского интерфейса. В результате мое приложение успешно запустилось. Но я не готов расстаться со всеми ценными отладочными данными, которые можно изучить с помощью пользовательского интерфейса Spark.
Кроме того, мне не удалось найти объяснения модели памяти драйвера Spark.
Вопрос в следующем: как мне сохранить данные отладки пользовательского интерфейса и не столкнуться с OOM в моем драйвере?