【问题标题】:Spring Batch saturating memorySpring Batch 饱和内存
【发布时间】:2014-05-27 14:48:42
【问题描述】:

更新:

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

我做了一个批处理,它从某些表格中存在的数据生成 pdf 文档并将 pdf 保存在表格中。批处理还可以,但要处理的数据很大,所以我决定将输入数据分成 8 组,并通过 8 个并行步骤独立处理 8 组。 每个步骤都有自己的阅读器(步骤“X”的名称为“readerX”),并且具有与其他步骤相同的处理器和写入器。

细化进行得很顺利,但我的客户说这个批处理使用了太多内存(他查看了 perfmon 中的“工作集”参数)。特别是批处理以 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>

谢谢

【问题讨论】:

  • 你是否得到标记的内存不足?
  • 在我的电脑上是的,在客户端服务器上没有.. 但是 7GB 对我的客户端来说太多了
  • 您能否提供有关该错误的任何见解?例外?线程转储?该配置在无数生产环境中使用都没有问题,所以我们需要更多的工作来继续。
  • 我服务器上没有异常,批处理执行成功。问题是客户端正在使用 perfmon 监视我的批处理,并说工作集达到 7GB 内存......而且太多了。
  • 这里的信息太少了。我们需要一些代码、线程转储等,否则无法为您提供帮助。

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


【解决方案1】:

如果你最终得到 OOM,首先从查看堆开始。

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

如果您能够使用更大的内存占用空间(例如您的客户端计算机)运行,请在占用大量内存(例如您提到的 7GB 或任何其他被认为较高的值 - 4、5、 6 等)。您应该能够在通过 JDK 中的 jconsole 等工具运行时调用它。

使用 HPROF 文件,您可以使用 JDK 提供的工具(例如 jhat)或更多基于 GUI 的工具(例如 eclipse 内存分析器)来检查它。这应该为您提供了一种很好(并且相对简单)的方法来找出什么坚持什么,并为减少足迹提供了一个起点。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 内存消耗异常的原因是什么?
    • 数据库连接配置错误...不知道为什么问题解决后...
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-09
      • 2023-03-25
      • 1970-01-01
      相关资源
      最近更新 更多