Opened on behalf of customer, Requesting for a change on implementing spring classes to reduce heap footprint on their BeanFactories, based on:
combination of (a) the number of BeanDefinitions and (b) the size of an individual BeanDefinition instance
BeanDefinitions has a number of Maps and Sets that are instantiated but are never populated i.e RootBeanDefinition's externallyManagedConfigMembers, externallyManagedInitMethods, externallyManagedDestroyMethods which are used to process annotations. since not all use annotation, may of the collections are never populated and contribute to heap footprint
This enhancement pertains to RootBeanDefinition and its ancestors, and other associated classes like MethodOverrides and ConstructorArgumentValues.
This is from RootBeanDefinition...
private final Set<Member> externallyManagedConfigMembers = Collections.synchronizedSet(new HashSet<Member>());
private final Set<String> externallyManagedInitMethods = Collections.synchronizedSet(new HashSet<String>());
private final Set<String> externallyManagedDestroyMethods = Collections.synchronizedSet(new HashSet<String>());
I believe these Sets are used to hold the results of scanning for @Autowired/@Inject, @PostConstruct and @PreDestroy respectively.
The vast majority of my BeanDefinition instances do not use those annotations so these Sets are empty. However, because these HashSets are always instantiated, and with default sizes, they take up considerable heap footprint, but with no functional benefit. If they were instantiated lazily (i.e. only when required), that would have a considerable benefit to our app, at the expense of slightly more complicated code and a (probably unmeasurable) performance impact as the bean defs are created.
The same applies to ConstructorArgumentValues.indexedArgumentValues when not using constructor-based dependency injection, MethodOverrides.overrides when not using lookup-method/replaced-method, and so on.
This is an area of optimization that we are tracking, next to concurrency optimizations and caching of pre-parsed metadata all over the core container. Admittedly the metadata footprint wasn't a high priority up to now since in our experience, the number of bean definitions is usually rather low, so the actual size of each definition doesn't have much impact. We'd be very interested in the actual numbers that you are seeing in your environment...
In any case, we are considering to give this another pass of optimization in Spring 3.1, not just for the BeanDefinition data structures but also with respect to the size of cached metadata in the container at runtime (where we are keeping post-processed BeanDefinition copies around, etc). We'll be careful not to do micro-optimizations, though; maintainable code is more important to us than squeezing every single byte.