Apache Ignite加载千万数据遇GC溢出 调JVM参数后IDE崩溃求助
Apache Ignite批量加载1000万数据内存溢出问题解决方案
核心问题分析
8GB物理内存环境下,你当前的配置(堆内存4G + 堆外数据区6G)总内存需求远超系统可用内存,导致内存耗尽触发GC过载或系统崩溃。同时DataStreamer和缓存配置存在可优化点,进一步加剧内存压力。
1. 内存配置调整(关键)
JVM堆内存优化
将堆内存下调至2G,避免与Ignite堆外数据区争夺内存,同时改用G1GC更适合批量数据场景:
-Xms2g -Xmx2g -Xmn1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
Ignite堆外数据区调整
将数据区最大容量从6G降至4.5G,预留至少1.5G给系统和JVM非堆内存:
regionCfg.setMaxSize(4831838208L); // 约4.5GB,计算方式:4.5*1024*1024*1024
2. DataStreamer写入优化
调整批量参数
开启批量写入优化,减少内存占用和网络开销:
public void streamBulkData(String cacheName, List<ProductLines> records) { try (IgniteDataStreamer<String, ProductLines> streamer = ignite.dataStreamer(cacheName)) { streamer.allowOverwrite(true); // 调整批量参数 streamer.perNodeBufferSize(10240); // 单节点缓冲区大小 streamer.perNodeParallelOperations(8); // 并行写入线程数 streamer.autoFlushFrequency(500); // 自动刷新间隔(毫秒) for (ProductLines record : records) { String key = record.getPan_no(); if (key != null) { streamer.addData(key, record); } } // 移除手动flush,DataStreamer会自动批量刷新 } catch (CacheException e) { System.err.println("数据写入缓存失败: " + e.getMessage()); } }
控制并发写入
原代码串行处理但用runAsync可能导致线程堆积,改用固定线程池控制并发数:
// 初始化固定线程池(根据CPU核心数调整,比如4) private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(4); public CompletableFuture<Void> processAllRecords() { long startTime = System.currentTimeMillis(); int pageNumber = 0; Page<ProductLines> page; List<CompletableFuture<Void>> futures = new ArrayList<>(); do { page = productLinesRepo.findRecordsWithPanNotNull(PageRequest.of(pageNumber++, BATCH_SIZE)); List<ProductLines> records = page.getContent(); if (!records.isEmpty()) { int finalPageNumber = pageNumber; CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { igniteCacheService.streamBulkData("poswavierCache", records); logger.info("已处理记录数: {}", (finalPageNumber - 1) * BATCH_SIZE + records.size()); }, EXECUTOR); futures.add(future); } } while (page.hasNext()); // 等待所有任务完成 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); long endTime = System.currentTimeMillis(); logger.info("总处理耗时: {} 毫秒", endTime - startTime); return CompletableFuture.completedFuture(null); }
实体对象轻量化
将JPA实体ProductLines转为DTO对象,移除懒加载代理和不必要的关联字段,减少单条记录内存占用。
3. Ignite服务器配置修正
修正缓存泛型类型
缓存配置泛型与实际存储类型不匹配,修正后避免类型转换开销:
CacheConfiguration<String, ProductLines> marksCacheCfg = new CacheConfiguration<>();
调整缓存模式(可选)
如果业务不需要全量数据复制,将REPLICATED改为PARTITIONED模式,大幅降低单节点内存压力:
marksCacheCfg.setCacheMode(CacheMode.PARTITIONED); marksCacheCfg.setBackups(1); // 根据需求设置备份数
关闭不必要的特性
生产环境关闭对等类加载,避免类加载内存泄漏:
cfg.setPeerClassLoadingEnabled(false);
4. 系统层面优化
- 直接用命令行启动Ignite服务器,避免IDE占用额外内存;
- Linux系统禁用swap分区,防止内存交换导致性能骤降和崩溃;
- 确保磁盘有足够空间存储Ignite持久化数据。
内容的提问来源于stack exchange,提问作者Dude Ramasamy
相关产品推荐
相关产品推荐

