Ответ
Задача: Оптимизация обработки больших CSV-файлов (10+ ГБ) в Java-приложении с ограниченной доступной памятью (heap ~2 ГБ). Стандартные библиотеки (OpenCSV) загружали весь файл в память, вызывая OutOfMemoryError.
Решение: Реализация потоковой (streaming) обработки с чанкингом и параллельным выполнением.
Ключевые шаги:
- Потоковое чтение: Использование
BufferedReaderдля построчного чтения файла без загрузки в память целиком. - Разбиение на чанки: Накопление строк в буферы фиксированного размера для последующей пакетной обработки.
- Параллельная обработка: Передача чанков в
ForkJoinPoolдля использования нескольких ядер CPU.
Упрощенная реализация:
public class LargeCsvProcessor {
private static final int CHUNK_SIZE = 1000;
private final ForkJoinPool forkJoinPool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
public void processFile(Path filePath) throws IOException {
try (BufferedReader reader = Files.newBufferedReader(filePath)) {
List<String> chunk = new ArrayList<>(CHUNK_SIZE);
String line;
while ((line = reader.readLine()) != null) {
chunk.add(line);
if (chunk.size() == CHUNK_SIZE) {
forkJoinPool.execute(new ChunkProcessorTask(new ArrayList<>(chunk)));
chunk.clear();
}
}
// Обработать оставшиеся строки
if (!chunk.isEmpty()) {
forkJoinPool.execute(new ChunkProcessorTask(chunk));
}
}
forkJoinPool.shutdown();
forkJoinPool.awaitTermination(1, TimeUnit.HOURS);
}
private static class ChunkProcessorTask implements Runnable {
private final List<String> chunk;
// ... логика обработки чанка (парсинг, валидация, сохранение)
}
}
Результат:
- Потребление памяти снижено на ~90% (теперь зависит от размера чанка, а не файла).
- Время обработки сокращено в 2.5 раза за счет параллелизма.
- Приложение стало стабильно работать в ограниченной среде.
Вывод: Для обработки больших данных необходимо применять потоковые модели и учитывать ограничения памяти на этапе проектирования.