Spring Batch饱和内存

时间:2014-05-27 14:48:42

标签: spring memory-leaks out-of-memory batch-processing spring-batch

更新:

我尝试添加一些细节,因为解决这个问题对我来说非常重要。

我制作了一个批处理,它根据一些表中存在的数据生成pdf文档,并将pdf保存在表中。批处理没问题,但要处理的数据很大,所以我决定将输入数据分成8组,并独立处理8组,并且有8个并行步骤。 每一步都有自己的阅读器(步骤“X”命名为“readerX”),并且具有与其他步骤一样的处理器和写入器。

精化很顺利,但是我的客户说这个批次使用了太多内存(他看着perfmon中的“Working Set”参数)。特别是批处理以300Mb的已用内存开始,然后使用的内存达到7GB,然后减少到2GB,批处理完成,分配内存为1 / 2GB。

我在这里粘贴了工作代码,希望有人能帮助我找到问题(我想我在调整并行处理工作时犯了一些错误。)

我是春季批次的新手,所以我为“糟糕的表情”道歉。

<job id="myJob"
    xmlns="http://www.springframework.org/schema/batch">
    <step id="step1" next="step2">
        <tasklet ref="task1" />
    </step>
    <step id="step2" next="step3">
        <tasklet ref="task2" />
    </step>
    <step id="step3" next="decider">
        <tasklet ref="task3" />
    </step>
    <decision id="decider" decider="StepExecutionDecider">
        <next on="CASE X"   to="split1" />
        <end on="*"/>   
    </decision>
    <split id="split1" task-executor="taskExecutor" next="endStep">
        <flow>
            <step id="EXEC1">
                <tasklet><chunk reader="reader1" processor="processor" writer="writer" commit-interval="100"/>
                <listeners>
                    <listener ref="Listner" />
                </listeners>
                </tasklet>
            </step>
        </flow>
        <flow>
            <step id="EXEC2">
                <tasklet><chunk reader="reader2" processor="processor" writer="writer" commit-interval="100"/>
                <listeners>
                    <listener ref="Listner" />
                </listeners>
                </tasklet>
            </step>
        </flow>
        <flow>
            <step id="EXEC3">
                <tasklet><chunk reader="reader3" processor="processor" writer="writer" commit-interval="100"/>
                <listeners>
                    <listener ref="Listner" />
                </listeners>

                </tasklet>
            </step>
        </flow>
         <flow>
            <step id="EXEC4">
                <tasklet><chunk reader="reader4" processor="processor" writer="writer" commit-interval="100"/>
                <listeners>
                    <listener ref="Listner" />
                </listeners>

                </tasklet>
            </step>
        </flow>
         <flow>
            <step id="EXEC5">
                <tasklet><chunk reader="reader5" processor="processor" writer="writer" commit-interval="100"/>
                <listeners>
                    <listener ref="Listner" />
                </listeners>
                </tasklet>
            </step>
        </flow>
         <flow>
            <step id="EXEC6">
                <tasklet><chunk reader="reader6" processor="processor" writer="writer" commit-interval="100"/>
                <listeners>
                    <listener ref="Listner" />
                </listeners>

                </tasklet>
            </step>
        </flow>
         <flow>
            <step id="EXEC7">
                <tasklet><chunk reader="reader7" processor="processor" writer="writer" commit-interval="100"/>
                <listeners>
                    <listener ref="Listner" />
                </listeners>
                </tasklet>
            </step>
        </flow>
         <flow>
            <step id="EXEC8">
                <tasklet><chunk reader="reader8" processor="processor" writer="writer" commit-interval="100"/>              
                <listeners>
                    <listener ref="Listner" />
                </listeners>
                </tasklet>
            </step>
        </flow>
    </split>
    <step id="endStep" next="decider">
        <tasklet ref="task4" >
            <listeners>
                <listener ref="Listner" />
            </listeners>
        </tasklet>
    </step>
</job>

<bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>

<bean id="reader1" class="class of the reader">
    <property name="idReader" value="1"/>   // Different for the 8 readers 
    <property name="subSet" value="10"/>    // Different for the 8 readers 
    <property name="dao" ref="Dao" />
    <property name="bean" ref="Bean" /> 
    [...] // Other beans
</bean>

由于

3 个答案:

答案 0 :(得分:2)

如果最终获得OOM,首先要查看堆。

使用-XX:+ HeapDumpOnOutOfMemoryError启动JVM以获取HPROF,然后您可以查看它以查看对象分配,大小等。当JVM退出OOM时,将生成此文件(可能需要一些时间,具体取决于尺寸)。

如果你能够使用更大的内存足迹(如客户端机器)运行,那么在消耗大量数据时会拍摄堆的快照,例如你提到的7GB(或任何其他被认为是高的值--4,5, 6等)。您应该能够在通过JDK等jconsole等工具运行时调用它。

使用HPROF文件,您可以使用JDK提供的工具(如jhat)或更多基于GUI的工具(如eclipse内存分析器)进行检查。这应该会给你一个很好的(并且相对容易的)方法来找出什么是什么,并提供减少足迹的起点。

答案 1 :(得分:0)

使用分析器并优化代码我成功地限制了内存消耗。谢谢大家!!!

答案 2 :(得分:0)

  

批处理没问题,但要处理的数据很大,所以我决定将输入数据分成8组,独立处理8组,并且有8个并行步骤。

如果您在同一台机器上并行处理,则不会减少内存占用量。所有数据同时存在于内存中。如果你想减少内存使用,你必须一个接一个地执行这些步骤。