Skip to content
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

Backport "Scoped-proxy memory leak w/ @Resource injection" [SPR-9363] #14000

Closed
spring-projects-issues opened this issue May 2, 2012 · 1 comment
Labels
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

@spring-projects-issues spring-projects-issues commented May 2, 2012

Chris Beams opened SPR-9363 and commented


This issue is a backport sub-task of #13814

Issue Links:

  • #14261 Regression: scoped beans being cached too aggressively

Referenced from: commits eed090e

1 votes, 1 watchers

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 27, 2012

Chris Beams commented

commit 90f6f6e060b6ce052dcad908f66e701499351fac
Author: Dridi Boukelmoune <dridi.b@laposte.net>
Commit: Chris Beams <cbeams@vmware.com>

    Fix scoped-proxy memory leak w/ @Resource injection
    
    Prior to this change, request-scoped components having
    @Resource-injected dependencies caused a memory leak in
    DefaultListableBeanFactory#dependenciesForBeanMap.
    
    Consider the following example:
    
        @Component
        @Scope(value="request", proxyMode=ScopedProxyMode.TARGET_CLASS)
        public class MyComponent {
    
            @Resource
            private HttpServletRequest request;
    
            // ...
        }
    
    The bean name for "MyComponent" will end up being
    'scopedTarget.myComponent', which will become a key in
    the #dependenciesForBeanMap structure.
    
    On the first request, the injected HttpServletRequest bean will be a
    proxy and will internally have a bean name of the form
    "$Proxy10@1a3a2a52". This name will be added to the Set value associated
    with the 'scopedTarget.myComponent' entry in #dependenciesForBeanMap.
    
    On the second request, the process will repeat, but the injected
    HttpServletRequest will be a different proxy instance, thus having a
    different identity hex string, e.g. "$Proxy10@5eba06ff". This name will
    also be added to the Set value associated with the
    'scopedTarget.myComponent' entry in #dependenciesForBeanMap, and this
    is the source of the leak: a new entry is added to the set on each
    request but should be added only once.
    
    This commit fixes the leak by introducing caching to
    CommonAnnotationBeanPostProcessor#ResourceElement similar to that already
    present in AutowiredAnnotationBeanPostProcessor#AutowiredFieldElement
    and #AutowiredMethodElement. Essentially, each ResourceElement instance
    now tracks whether it has been created, caches the ultimate value to be
    injected and returns it eagerly if necessary. Besides solving the memory
    leak, this has the side effect of avoiding unnecessary proxy creation.
    
    This fix also explains clearly why injection into request-scoped
    components using @Autowired never suffered this memory leak: because the
    correct caching was already in place. Because @Resource is considerably
    less-frequently used than @Autowired, and given that this particular
    injection arrangement is relatively infrequent, it becomes
    understandable how this bug has been present without being reported
    since the introduction of @Resource support in Spring 2.5: developers
    were unlikely to encounter it in the first place; and if they did, the
    leak was minor enough (adding strings to a Set), that it could
    potentially go unnoticed indefinitely depending on request volumes and
    available memory.
    
    Issue: SPR-9176

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
1 participant