Java 在Spring中,批处理ThreadPoolTaskExecutor引用不会被垃圾收集
我正在处理Spring批处理,并使用ThreadPoolTaskExecutor来分叉多个线程。 这些文件很大,比如175MB,我处理的是很多字符串对象。 由于此OutOfMemory错误被抛出 下面的配置将调用1个线程来处理1个文件(customDBPartitioner正在拾取文件) 以下是配置:Java 在Spring中,批处理ThreadPoolTaskExecutor引用不会被垃圾收集,java,multithreading,out-of-memory,spring-batch,threadpoolexecutor,Java,Multithreading,Out Of Memory,Spring Batch,Threadpoolexecutor,我正在处理Spring批处理,并使用ThreadPoolTaskExecutor来分叉多个线程。 这些文件很大,比如175MB,我处理的是很多字符串对象。 由于此OutOfMemory错误被抛出 下面的配置将调用1个线程来处理1个文件(customDBPartitioner正在拾取文件) 以下是配置: <bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTa
<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(preprocessutil.getAvailableMemory()
我尝试的是,如果没有足够的内存,那么不要执行处理下一个文件的步骤
当可用内存低于memoryRequired时,线程进入睡眠模式,但GC从未被调用,相反,内存一直在减少
有人可以帮助我,让我知道这里的问题是什么,如何回收内存来处理文件
编辑:
在JvisualVM中,大部分内存由字符串/字符占用
块大小为1
也就是说:我要求每个线程一次读取/处理一个文件。文件大小从KB到100 MB不等。
我无法选择逐行处理文件的选项,因为在处理时我必须参考文件中的不同章节。 这是来自读卡器的代码,它在一个块中读取一个文件
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文件=新的StringBuilder()
试一试{
//我也试过这个。
//append(FileUtils.readFileToString(resource.getFile());
logger.info(“文件大小:“+resource.getFilename()+”为“+FileUtils.sizeOf(resource.getFile())/1024+”KB”);
已同步(UnixFileItemReader.class){
lineIterator=FileUtils.lineIterator(resource.getFile());
/*while(preprocessutil.getAvailableMemoryNoLogs()
在StringBuilder中读取整个文件后,我在处理器中进行了大量的模式匹配。要解决这个问题,最后可能需要使用Eclipse MAT或其他工具分析jmap dunp文件。因为问题可能与代码的每个细节都有关系
这里我只给出一个可能的原因:ExecutorService有一个用于等待作业的阻塞队列,这些等待作业还保留内存。因此,如果提交作业太快,很容易内存不足。块大小有多大?此外,多线程读取文件通常不会从性能上获得太多好处。您发布的代码中没有内存泄漏。您应该发布实际的I/O代码或使用哈希映射的代码。我的第一个猜测是,您没有关闭正在将文件读入内存的流。我只是编辑了我的问题以掩盖上述问题。情况似乎并非如此,我还尝试了sleep方法来降低执行速度。