我正在使用Spring Batch並使用ThreadPoolTaskExecutor來分叉多個線程。 文件很大,像175 MB,我正在處理大量的字符串對象。 由於此OutOfMemory錯誤正在拋出。在Spring批處理ThreadPoolTaskExecutor引用不被垃圾收集
下面的配置將調用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之後,線程進入睡眠模式,但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後,我做的很多模式匹配的處理器。
你的塊大小有多大?而且,多線程讀取文件通常不會通過性能獲得太多好處。 –
您的內存泄漏不在您發佈的代碼中。您應該發佈實際的I/O代碼或使用散列映射的代碼。我的第一個猜測是你沒有關閉將文件讀入內存的流。 – ngreen
我剛剛編輯了我的問題來掩蓋以上問題。 – Ramandeep