Spring web thread using a lot of memory
Webflow application (2.3.1) requires a lot of memory for each new stream that we open through the browser.
The screenshot below shows our application memory usage. When the application starts up, it takes an initial 400 MB. After that, we open 4 individual identical Webflow TEST pages in the browser, each of which requires about 90 MB of additional memory.
Each test page starts 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>
JSP test pages are also very basic, just blank with one line of text.
When we currently set the JVM memory to 1.5 GB, the application will end up crashing on the server with OutOfMemoryExceptions after opening about 15 different threads. 1.5 Gb seems a bit big considering the low complexity of the screens.
We are wondering if we expect the amount of Webflow Web resources for these simple streams / pages and if we should just assign more memory to the server JVM. If not, we would like to know how we can reduce the use of this memory.
Below is the whole web stream configuration.
We tried to add the run-repository-repository tag and played with the max-snapshot and max-execution values, but even the most conservative settings don't change the memory usage we see.
<?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>
source to share
When Spring Web Flow starts a new flow, it basically creates a new BeanFactory
one that loads the xml file and imports any additional XML files. The newly built BeanFactory
has a context DispatcherServlet
like its parent.
Now the problem is that the bean factory instantiates all beans, even the ones specified in the imported XML files.
<bean-import resource="../flow-beans.xml"/>
If there are many beans, then they will be duplicated for each thread instance. In general, you don't want all of your beans to be duplicated and persisted across user sessions.
Extract the singleton beans from flow-beans.xml
and place them in the normal application context, they are still available from the thread definition. Or you can simply add flow-beans.xml
to the list of files loaded when the application starts.
source to share