Skip to content

OutOfMemoryError using ConfigurableListableBeanFactory.destroyBean [SPR-5139] #9812

@spring-projects-issues

Description

@spring-projects-issues

janardhanan vembunarayanan opened SPR-5139 and commented

In my application I am using Spring as a container to store objects.
During the life cycle of my application the values of the these objects can change and I am using the destroyBean() and removeBeanDefinition() of ConfigurableListableBeanFactory and recreating the same using registerBeanDefinition(..).

If I do this process in a for loop continuously I am getting OutOfMemoryError. The reason is in the class DefaultSingletonBeanRegistry the following data structures are growing continuously. Is this a known bug in Spring API destroyBean() and removeBeanDefinition()?

I have attached the test cases and the spring xml file I used for causing this issue. They are in the same file SpringBug.txt.

This issue is coming when I have a Singleton and it has an inner bean.

/** Map between dependent bean names: bean name --> Set of dependent bean names */
private final Map dependentBeanMap = CollectionFactory.createConcurrentMapIfPossible(16 );

/** Map between depending bean names: bean name --> Set of bean names for the bean's dependencies */
private final Map dependenciesForBeanMap = CollectionFactory.createConcurrentMapIfPossible(16 );

Test Case for the crash is given below along with the Spring configuration.

<code>

package com.debug.spring.modified;

import org.junit.Test;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringBugModified {
private long objectid = 1;

@Test
public void testSpringBug() throws Exception {
	ClassPathXmlApplicationContext configuration = new ClassPathXmlApplicationContext(
			new String[] { "classpath:com/debug/spring/modified/testspringbug.xml" });
	System.out.println("*** Singleton ***");
	TestSingletonBeanBug tBeanSingleton = (TestSingletonBeanBug) configuration.getBean("TestBeanSingletonBug");
	count(configuration, tBeanSingleton.getInnerBean());
	for (;;) {
		configuration.getBeanFactory().destroyBean("TestBeanSingletonBug",tBeanSingleton);
		((DefaultListableBeanFactory) configuration.getBeanFactory()).removeBeanDefinition("TestBeanSingletonBug");
		BeanDefinition beanDefinitionSingleton = createTestSingletonBeanBug();
		((DefaultListableBeanFactory) configuration.getBeanFactory()).registerBeanDefinition("TestBeanSingletonBug",beanDefinitionSingleton);
		TestSingletonBeanBug singletonBean = (TestSingletonBeanBug) configuration.getBean("TestBeanSingletonBug");
		count(configuration, singletonBean.getInnerBean());
	}
}

private void count(ListableBeanFactory factory, TestInnerBean tib) {
	System.out.println("Total number of beans: " + factory.getBeanDefinitionCount());
	System.out.println("Total number of TestInnerBean definitions: " + factory.getBeanNamesForType(TestInnerBean.class,true, false).length);
	System.out.println("ObjectID latest TestInnerBean: " + tib.getCount());
}

private BeanDefinition createTestSingletonBeanBug() throws Exception {
	AbstractBeanDefinition beanDefinitionSingleton = BeanDefinitionReaderUtils.createBeanDefinition(null,"com.debug.spring.modified.TestSingletonBeanBug",getClass().getClassLoader());
	MutablePropertyValues propssingleton = new MutablePropertyValues();
	propssingleton.addPropertyValue("count", "600");
	beanDefinitionSingleton.setPropertyValues(propssingleton);
	beanDefinitionSingleton.setAbstract(false);
	beanDefinitionSingleton.setLazyInit(true);
	PropertyValue pv = new PropertyValue("innerBean", createTestInnerBean());
	beanDefinitionSingleton.getPropertyValues().addPropertyValue(pv);
	return beanDefinitionSingleton;
}

@SuppressWarnings("unused")
private BeanDefinition createTestInnerBean() throws Exception {
	objectid++;
	AbstractBeanDefinition innerBeanDefinition = BeanDefinitionReaderUtils.createBeanDefinition(null,"com.debug.spring.modified.TestInnerBean", getClass().getClassLoader());
	MutablePropertyValues innerbeanproperties = new MutablePropertyValues();
	innerbeanproperties.addPropertyValue("count", this.objectid);
	innerBeanDefinition.setPropertyValues(innerbeanproperties);
	BeanDefinitionHolder bdh = new BeanDefinitionHolder(innerBeanDefinition, TestInnerBean.class.getSimpleName()+ objectid, null);
	return innerBeanDefinition;
}

}

class TestInnerBean {
private int count;

public TestInnerBean() {
}

public int getCount() {
	return count;
}

public void setCount(int count) {
	this.count = count;
}

}

class TestSingletonBeanBug {

private int count;
private TestInnerBean innerBean;

public TestSingletonBeanBug() {
}

public int getCount() {
	return count;
}

public TestInnerBean getInnerBean() {
	return innerBean;
}

public void setCount(int count) {
	this.count = count;
}

public void setInnerBean(TestInnerBean innerBean) {
	this.innerBean = innerBean;
}

}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-lazy-init="true">

<bean id="TestBeanSingletonBug" singleton="true"
    	class="com.debug.spring.modified.TestSingletonBeanBug">
    	<property name="count" value="0"/>
    	<property name="innerBean">
	    	<bean class="com.debug.spring.modified.TestInnerBean">
	    		<property name="count" value="0"/>
	    	</bean>
	    </property>
</bean>

</beans>
</code>


Affects: 2.5.4, 2.5.5

Attachments:

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions