我正在使用 Spring Batch 并使用 ThreadPoolTaskExecutor 来创建多个线程。 这些文件很大,大约 175 MB,我正在处理很多字符串对象。 由于此 OutOfMemory 错误被抛出。
下面的配置将调用 1 个线程来处理 1 个文件(customDBPartitioner 正在拾取文件)。
这是配置:
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="3" />
<property name="maxPoolSize" value="3" />
</bean>
<step id="unixPartitionerStep">
<partition step="unixItemStep" partitioner="customDBPartitioner">
<handler grid-size="10" task-executor="threadPoolTaskExecutor" />
</partition>
</step>
<listeners>
<listener ref="unixJobListener" />
</listeners>
因此,当调用此步骤时:3 个线程开始处理文件,以检查内存,我在 stepListener 中放置了一个条件。
while(preProcessorUtil.getAvailableMemory() < minimumMemoryRequired) {
logger.info("Thread going to sleep as memory is not enough - " + inputFile.getFilename());
Thread.sleep(5000);
}
我正在尝试的是如果没有足够的内存可用则不要执行处理下一个文件的步骤。
可用内存低于 memoryRequired 后,线程进入 hibernate 模式,但 GC 永远不会被调用,内存会继续减少。
有人可以帮忙告诉我这里的问题是什么,如何回收内存来处理文件?
编辑: 在 JvisualVM 中,大部分内存被 Strings/chars 占用
block 大小为 1
那就是:我要求每个线程一次读取/处理一个文件。文件大小从 KB 到 100 MB 不等。
我无法选择逐行处理文件的选项,因为在处理时
我必须引用文件中的不同部分。
这是 Reader 的代码,它正在读取一个 block 中的一个文件
StringBuilder file = new StringBuilder()
try {
// I tried this as well.
//file.append(FileUtils.readFileToString(resource.getFile()));
logger.info("Size of file : "+ resource.getFilename() +" is " + FileUtils.sizeOf(resource.getFile())/1024 + " KB");
synchronized(UnixFileItemReader.class) {
lineIterator = FileUtils.lineIterator(resource.getFile());
/*while(PreProcessorUtil.getAvailableMemoryNoLogs() < minimumMemoryRequired) {
Thread.sleep(5000);
}*/
while (lineIterator.hasNext()) {
file.append(lineIterator.nextLine()).append("\r\n");
}
}
} catch(Exception ex) {
ex.printStackTrace();
file = null;
throw ex;
} finally {
LineIterator.closeQuietly(lineIterator);
}
在 StringBuilder 中读取整个文件后,我在处理器中进行大量模式匹配。
最佳答案
要解决这个问题,最后可能需要用Eclipse MAT或其他一些工具分析jmap dunp文件。因为问题可能与代码的每个细节有关。
这里我只是给出一个可能的原因:ExecutorService有一个BlockingQueue用于等待作业,这些等待作业也是保持内存的。所以如果提交作业的速度太快,很容易出现内存不足的情况。
关于java - 在 Spring Batch 中,ThreadPoolTaskExecutor 引用不会被垃圾回收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44297715/