3

Our Webflow (2.3.1) application is claiming a lot of memory for each new flow that we open through the browser.

The screenshot below shows our application's memory use. When the application starts it takes an initial 400 Mb. After that we open 4 individual, identical Webflow TEST pages in the browser which each claim about 90Mb of extra memory..

enter image description here

Each test page is started from its own simple flow definition:

<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns="http://www.springframework.org/schema/webflow"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
                                  http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd" start-state="start"> 
    <view-state id="start" view="test/test1">
    </view-state>
    <end-state id="end"/>
    <bean-import resource="../flow-beans.xml"/>
</flow>

The JSP test pages are also very simple, just empty with one line of text.

When we currently set the JVM memory to 1.5Gb the application eventually crashes on the server with OutOfMemoryExceptions after opening about 15 different flows. 1.5 Gb seems a bit much, regarding the low complexity of our screens..

We are wondering if the amount of memory Webflow seems to claim for these simple flows/pages is expected and if we should therefore just assign more memory to the server JVM. If not, we would like to know how we can decrease this memory usage.

Below is our entire webflow configuration.

We have tried adding a flow-execution-repository tag and played around with the max-executions-snapshots and max-executions values, but even the most conservative settings don't change the memory usage we are seeing.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:webflow="http://www.springframework.org/schema/webflow-config"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/webflow-config
       http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.3.xsd
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <!-- Launches new flow executions and resumes existing executions. -->

    <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
    </webflow:flow-executor>

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:our.properties" />
        <property name="placeholderPrefix" value="$xxxx"></property>
    </bean>

    <tx:annotation-driven transaction-manager="$xxxx{txManager}" />

    <!-- Creates the registry of flow definitions for this application -->
    <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
        <webflow:flow-location-pattern value="classpath:flows/**/*-flow.xml" />
    </webflow:flow-registry>

    <bean id="viewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
        <property name="viewResolvers" ref="viewResolver" />
    </bean>

    <bean id="expressionParser" class="org.springframework.expression.spel.standard.SpelExpressionParser">
        <constructor-arg name="configuration">
          <bean class="org.springframework.expression.spel.SpelParserConfiguration">
            <constructor-arg name="autoGrowCollections" value="true" />
            <constructor-arg name="autoGrowNullReferences" value="false" />
          </bean>
        </constructor-arg>
    </bean>

    <bean id="webflowExpressionParser" class="org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser">
        <constructor-arg name="expressionParser" ref="expressionParser" />
    </bean>

    <webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="viewFactoryCreator" validator="validator" expression-parser="webflowExpressionParser"/>

    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />


    <bean id="projectVersion" class="our.company.versions.ProjectVersionUtil">
        <property name="xxxxVersion" value="$xxxx{xxxx.version}" />
        <property name="systemConfigurationDao">    
            <ref bean="SystemConfigurationDao"/>
        </property>
    </bean>

</beans>
Julius
  • 2,784
  • 6
  • 32
  • 54
  • 2
    I suspect you are basicly reloading singletons each time you need it. I suspect that your `flow-beans.xml` contains beans that should be application singletons but are reloaded for each flow instance. – M. Deinum Sep 09 '14 at 10:40
  • I just put a breakpoint in one of the binders' constructors and it hits with every new flow we access, so it seems you are right. I am going to investigate this further and will come back with more later. Thanks so much. – Julius Sep 09 '14 at 11:00
  • Also, show how web.xml and *-flow xmls are configured. – Prasad Sep 09 '14 at 13:55
  • @M.Deinum: we are now loading flow-beans.xml from web.xml as a normal application context and we have removed all bean-import tags from our flow definitions. Result: 60-70% less memory usage. Could you copy your answer into a new answer, then I'll mark it as the solution. Thanks again. – Julius Sep 10 '14 at 07:05

1 Answers1

2

When Spring Web Flow starts a new flow it basically constructs a new BeanFactory which loads the xml file and imports any additional xml files. The newly constructed BeanFactory has the context of the DispatcherServlet as its parent.

Now the problem with this is that a the bean factory constructs instances of all the beans even those defined in imported XML files.

<bean-import resource="../flow-beans.xml"/>

If there are a lot of beans in there those will be duplicated for each flow instance. In general you don't want your all of your beans duplicated and stored in the users sessions.

Remove the singleton beans from the flow-beans.xml and put them in the normal application context, they are still referable from within the flow definition. Or you could simply add the flow-beans.xml to the list of files loaded at startup of your application.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224