我并行运行约18.000个春季作业,每个作业都有一个步骤。每个步骤都包括从文件中读取,转换和操纵这些值并将其写入Mongo和MySQL数据库,这并不常见。所有工作完成后,内存消耗保持在20GB 使用的20GB,并且留在那里。我构造我的春季批处理成员如下:
@Autowired
public ArchiveImportManager(final JobRepository jobRepository, final BlobStorageConfiguration blobConfiguration,
final JobBuilderFactory jobBuilderFactory, final StepBuilderFactory stepBuilderFactory,
final ArchiveImportSettings settings) {
this.jobBuilderFactory = jobBuilderFactory;
this.stepBuilderFactory = stepBuilderFactory;
this.jobLauncher = new SimpleJobLauncher();
final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(THREAD_POOL_SIZE);
threadPoolTaskExecutor.setMaxPoolSize(THREAD_POOL_SIZE);
threadPoolTaskExecutor.setQueueCapacity(THREAD_POOL_QUEUE);
threadPoolTaskExecutor.initialize();
this.jobLauncher.setTaskExecutor(threadPoolTaskExecutor);
this.jobLauncher.setJobRepository(jobRepository);
}
我创建一个作业如下:
private Job createImportJob(final ArchiveResource archiveResource, final int current, final int archiveSize) {
final String name = "ImportArchiveJob[" + current + "|" + archiveSize + "]"
+ new Date(System.currentTimeMillis());
final Step step = this.stepBuilderFactory
.get(name)
.<ArchiveResource, ArchiveImportSaveData> chunk(1)
.reader(getReader(archiveResource, current, archiveSize))
.processor(getProcessor(current, archiveSize))
.writer(getWriter(current, archiveSize))
.build();
return this.jobBuilderFactory
.get(name)
.flow(step)
.end()
.build();
}
并在循环中启动所有作业:
private void startImportJobs(final List<ArchiveResource> archives) {
final int size = archives.size();
for (int i = 0; i < size; i++) {
final ArchiveResource ar = archives.get(i);
final Job j = createImportJob(ar, i, size);
try {
this.jobLauncher.run(j, new JobParametersBuilder()
.addDate("startDate", new Date(System.currentTimeMillis()))
.addString("progress", "[" + i + "|" + size + "]")
.toJobParameters());
} catch (final JobExecutionAlreadyRunningException e) {
log.info("Already running", e);
} catch (final JobRestartException e) {
log.info("Restarted", e);
} catch (final JobInstanceAlreadyCompleteException e) {
log.info("ALready completed", e);
} catch (final JobParametersInvalidException e) {
log.info("Parameters invalid", e);
}
}
}
我是否必须以某种方式释放记忆或删除作业后?我不明白为什么记忆消耗保持很高。
最好的问候
从HTOP中获取该信息并从中获取任何信息并不是一个好主意。这是因为Java内存管理。
Java从操作系统中分配内存并在内部管理该内存。这全都连接到诸如垃圾收集和世代内存模型之类的术语。
基本上,如果您通过在应用程序中删除对这些对象的引用来释放内存,则不会立即设置内存。只有当Java分配的内存已满时,才会触发垃圾收集周期。该周期不会(一定)释放针对OS的内存。第一步将使您的Java程序可用,同时仍然坚持使用OS。
如果Java VM中的启发式词确定,您分配了太多的内存,它将向操作系统释放内存,但这是您不应依靠的。
这就是为什么您仍然会看到Java过程保留的20G。而且,如果没有仔细观察该应用程序,您甚至都不知道该内部内部释放或填满了死对象。
如果您想更好地了解应用程序的内存脚印,我建议您执行以下操作:诸如JConsole或JvisualVM之类的工具(在这里您需要Visual GC插件)允许您检查内存的内部。由Java VM分配。在该内存中,对于称为旧或终身任期的内存区域,与您的问题无关(如果您很好奇,则其他所有内容都与您的问题无关。如果您想触发垃圾收集以删除已经死亡(但尚未清理的对象),要么在您的应用程序中明确调用System.gc()
,要么通过JConsole或JvisualVM触发它(都有一个按钮可以这样做)。垃圾收集后直接的内存消耗是您当前正在寻找的数字。