Кейс: экспорт отчёта за год клал приложение по памяти на 200 строках

Эндпоинт отдавал годовой отчёт в Excel. На тесте с сотней строк работал за секунды. В проде на клиенте с высокой активностью — OutOfMemoryError на отчёте из двухсот тысяч строк, хотя heap был выставлен щедро.

Причина была не в объёме данных как таком, а в том, как их собирали перед отдачей. Сервис грузил весь результат запроса в List, затем строил из него Apache POI Workbook целиком в памяти, и только потом писал его в OutputStream ответа.

List rows = orderRepository.findAllForYear(year);

Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet();

for (OrderRow row : rows) { writeRow(sheet, row); }

workbook.write(response.getOutputStream());

Проблема тройная. Во-первых, весь результат запроса материализуется в List перед обработкой — вместо потоковой выборки из БД через курсор. Во-вторых, стандартный XSSFWorkbook держит всё дерево XML-объектов строки в памяти одновременно. В-третьих, ответ клиенту начинает писаться только после того, как весь Workbook готов — то есть пиковое потребление памяти складывается из всех трёх слоёв разом.

Решение — заменить XSSFWorkbook на SXSSFWorkbook, который держит в памяти окно из настраиваемого числа последних строк и сбрасывает остальные на диск, и заменить findAllForYear на потоковую выборку через Stream с курсором на уровне JDBC, чтобы не грузить весь список сразу.

Что спросят следом на разборе такого инцидента: «а почему просто не увеличили heap, если экспорт — редкая операция раз в год?» Ответ: увеличение heap решает конкретный случай с двумя сотнями тысяч строк, но не убирает архитектурную проблему — рост объёма данных клиента снова упрётся в лимит, только позже. Потоковая обработка не имеет верхней границы по объёму входных данных вообще.

OutOfMemoryError на экспорте почти никогда не про размер heap — почти всегда про то, что весь набор данных пытаются держать в памяти одновременно вместо потоковой обработки.

Тренажёр: 600 вопросов, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки