-
Notifications
You must be signed in to change notification settings - Fork 38.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Revise cache safety check to avoid performance regression in EAR packaged applications on WildFly [SPR-16714] #21255
Comments
Juergen Hoeller commented We'll see what we can do about this. Please note that the 3.2.x line at its end-of-life already, so potential measures would only be applied to the upcoming 4.3.17 and 5.0.6 releases. |
Diego Pettisani commented Thanks Jurgen for the quick response and for having accepted the issue. Our program already planned a migration to Spring 4, so a fix for that streams will be suitable for us too. As short-term solution for an upcoming release we are thinking to patch the DefaultListableBeanFactory class by removing that if condition. Parent and child contexts have the same lifecycle in our app, so we should not suffer of the memory leak raised in the #16145. Of course, the patch will be our last option and a temporary solution. |
Juergen Hoeller commented This seems to be rather specific to WildFly since it is generally unusual to have a valid In terms of potential solutions, we could consider inverting our cache-safety algorithm to only consider a |
Juergen Hoeller commented I eventually went with a combination of the original parent traversal and the inverted algorithm, being able to clearly and efficiently identify many common |
Diego Pettisani commented Thanks Juergen, we are going forward to download the next Spring 4 release. I am sure that our program will accelerate the migration from Spring 3.2.x to Spring 4.3.x. For a very short-term solution to implement in the our Spring 3.2.16 app we extended the public class CustomListableBeanFactory extends DefaultListableBeanFactory {
private final Map<Class<?>, String[]> allBeanNamesByType =
new ConcurrentHashMap<Class<?>, String[]>(64);
private final Map<Class<?>, String[]> singletonBeanNamesByType =
new ConcurrentHashMap<Class<?>, String[]>(64);
public CustomListableBeanFactory() {
super();
}
public CustomListableBeanFactory(BeanFactory parentBeanFactory) {
super(parentBeanFactory);
}
@Override
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return super.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
}
Map<Class<?>, String[]> cache = (includeNonSingletons ? this.allBeanNamesByType
: this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = super.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
cache.put(type, resolvedBeanNames);
return resolvedBeanNames;
}
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
super.registerSingleton(beanName, singletonObject);
clearByTypeCache();
}
@Override
public void destroySingleton(String beanName) {
super.destroySingleton(beanName);
clearByTypeCache();
}
private void clearByTypeCache() {
this.allBeanNamesByType.clear();
this.singletonBeanNamesByType.clear();
}
} By using this implementation, potentially, we could suffer of the memory leak raised in the #16145 but we never never never do an hot-deploy of an application having a child Spring context, so we should be safe for that memory leak. Do you agree? I attached the sources that we will use for the temporary solution in our Spring 3.2.16 app, in the meanwhile we will plan the Spring 4.3.x migration. |
Diego Pettisani opened SPR-16714 and commented
We had a performance issue after upgraded from Spring 3.2.2 to 3.2.16.
Our application is packaged in an EAR file having several "skinny" WARs, so the content inside the EAR is:
In each web.xml file we have this configuration:
The parent context has several hundred of beans.
We developed an internal platform for our applications that often calls the following BeanFactory method:
In turn, The above getBean(Class) method calls the following DefaultListableBeanFactory method:
After upgraded to Spring 3.2.16 the call to the above getBeanNamesForType() method was very slow and CPU consuming. The root cause is the following class loader check:
added for fixing a memory leak highlighted in the #16145 and released in Spring 3.2.9.
The check inside the if condition:
returns always false because:
So the following internal caches of the DefaultListableBeanFactory class:
will always be empty and they will never be used.
Furthermore informations:
Affects: 3.2.18, 4.3.16, 5.0.5
Attachments:
Issue Links:
Referenced from: commits 46e3a91, 2989f01, 0efa7a0, 295929c
Backported to: 4.3.17
The text was updated successfully, but these errors were encountered: