You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tuscany.apache.org by "Scott Kurz (JIRA)" <de...@tuscany.apache.org> on 2008/10/06 20:43:44 UTC

[jira] Created: (TUSCANY-2630) memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl

memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl
----------------------------------------------------------------------------

                 Key: TUSCANY-2630
                 URL: https://issues.apache.org/jira/browse/TUSCANY-2630
             Project: Tuscany
          Issue Type: Bug
          Components: Java SCA Core Runtime
            Reporter: Scott Kurz


We can end up with an unbounded chain of RuntimeWireImpls  because of the way the 'cachedWire' field is handled to cache a callback wire.

The problem arises with a sequence like:

1) Thread A calls CallbackReferenceImpl.getCallbackWire(), which results in a wire.clone() and then the boundWire is "cached" via:
  ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);

2) Thread B calls the same method on the same 'wire' instance, but because the cachedWire is in-use, it does its own wire.clone(),
making a shallow copy of wire's 'cachedWire'.

3) Only now does Thread A finish and call:     ((RuntimeWireImpl)wire).releaseWire();     (Nothing special happens here.  I'm just pointing out
that since 2) happened first, the cached object was in-use and a new clone was made.

4) When Thread B gets to the end of RuntimeWireImpl.cloneAndBind() it calls:
  ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);

The net result is that the original wire has a ref, 'cachedWire' to the clone made in Thread B, which in turn has a ref to the clone made from Thread A.

This illustrates the problem, as this can recursively grow unbounded.

---------

A simple solution would seem to be to null out the 'cachedWire' field towards the end of RuntimeWireImpl.clone().   Maybe there's an even better one.




-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


Re: [jira] Commented: (TUSCANY-2630) memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl

Posted by Simon Laws <si...@googlemail.com>.
On Tue, Oct 7, 2008 at 2:17 PM, Scott Kurz (JIRA) <de...@tuscany.apache.org>wrote:

>
>    [
> https://issues.apache.org/jira/browse/TUSCANY-2630?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12637471#action_12637471]
>
> Scott Kurz commented on TUSCANY-2630:
> -------------------------------------
>
> Thanks for taking a look.   Not understanding this code real well, I have
> to take it for granted that we have a good reason for not sharing the
> callback wire across threads, (though I was half-wondering if that might
> have been an old assumption that someone might realize is no longer needed).
>
> I don't know how to contribute a test showing this timing-dependent issue;
>  I have to use the debugger to step through to recreate.  However, I would
> say I've confirmed this fixes the leak in my environment.
>
>
>
> > memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone()
> impl
> >
> ----------------------------------------------------------------------------
> >
> >                 Key: TUSCANY-2630
> >                 URL: https://issues.apache.org/jira/browse/TUSCANY-2630
> >             Project: Tuscany
> >          Issue Type: Bug
> >          Components: Java SCA Core Runtime
> >            Reporter: Scott Kurz
> >
> > We can end up with an unbounded chain of RuntimeWireImpls  because of the
> way the 'cachedWire' field is handled to cache a callback wire.
> > The problem arises with a sequence like:
> > 1) Thread A calls CallbackReferenceImpl.getCallbackWire(), which results
> in a wire.clone() and then the boundWire is "cached" via:
> >   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> > 2) Thread B calls the same method on the same 'wire' instance, but
> because the cachedWire is in-use, it does its own wire.clone(),
> > making a shallow copy of wire's 'cachedWire'.
> > 3) Only now does Thread A finish and call:
> ((RuntimeWireImpl)wire).releaseWire();     (Nothing special happens here.
>  I'm just pointing out
> > that since 2) happened first, the cached object was in-use and a new
> clone was made.
> > 4) When Thread B gets to the end of RuntimeWireImpl.cloneAndBind() it
> calls:
> >   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> > The net result is that the original wire has a ref, 'cachedWire' to the
> clone made in Thread B, which in turn has a ref to the clone made from
> Thread A.
> > This illustrates the problem, as this can recursively grow unbounded.
> > ---------
> > A simple solution would seem to be to null out the 'cachedWire' field
> towards the end of RuntimeWireImpl.clone().   Maybe there's an even better
> one.
>
> --
> This message is automatically generated by JIRA.
> -
> You can reply to this email to add a comment to the issue online.
>

IIRC it's because the callbacks for different threads can (will) have
different destinations and hence the wires are configured differently.

Simon

[jira] Commented: (TUSCANY-2630) memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl

Posted by "Scott Kurz (JIRA)" <de...@tuscany.apache.org>.
    [ https://issues.apache.org/jira/browse/TUSCANY-2630?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12638070#action_12638070 ] 

Scott Kurz commented on TUSCANY-2630:
-------------------------------------

Fixed in trunk in r702984.

> memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl
> ----------------------------------------------------------------------------
>
>                 Key: TUSCANY-2630
>                 URL: https://issues.apache.org/jira/browse/TUSCANY-2630
>             Project: Tuscany
>          Issue Type: Bug
>          Components: Java SCA Core Runtime
>            Reporter: Scott Kurz
>
> We can end up with an unbounded chain of RuntimeWireImpls  because of the way the 'cachedWire' field is handled to cache a callback wire.
> The problem arises with a sequence like:
> 1) Thread A calls CallbackReferenceImpl.getCallbackWire(), which results in a wire.clone() and then the boundWire is "cached" via:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> 2) Thread B calls the same method on the same 'wire' instance, but because the cachedWire is in-use, it does its own wire.clone(),
> making a shallow copy of wire's 'cachedWire'.
> 3) Only now does Thread A finish and call:     ((RuntimeWireImpl)wire).releaseWire();     (Nothing special happens here.  I'm just pointing out
> that since 2) happened first, the cached object was in-use and a new clone was made.
> 4) When Thread B gets to the end of RuntimeWireImpl.cloneAndBind() it calls:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> The net result is that the original wire has a ref, 'cachedWire' to the clone made in Thread B, which in turn has a ref to the clone made from Thread A.
> This illustrates the problem, as this can recursively grow unbounded.
> ---------
> A simple solution would seem to be to null out the 'cachedWire' field towards the end of RuntimeWireImpl.clone().   Maybe there's an even better one.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (TUSCANY-2630) memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl

Posted by "Simon Laws (JIRA)" <de...@tuscany.apache.org>.
    [ https://issues.apache.org/jira/browse/TUSCANY-2630?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12640515#action_12640515 ] 

Simon Laws commented on TUSCANY-2630:
-------------------------------------

committed to 1.3.3 at revision: 705595  


> memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl
> ----------------------------------------------------------------------------
>
>                 Key: TUSCANY-2630
>                 URL: https://issues.apache.org/jira/browse/TUSCANY-2630
>             Project: Tuscany
>          Issue Type: Bug
>          Components: Java SCA Core Runtime
>            Reporter: Scott Kurz
>             Fix For: Java SCA-1.3.3
>
>
> We can end up with an unbounded chain of RuntimeWireImpls  because of the way the 'cachedWire' field is handled to cache a callback wire.
> The problem arises with a sequence like:
> 1) Thread A calls CallbackReferenceImpl.getCallbackWire(), which results in a wire.clone() and then the boundWire is "cached" via:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> 2) Thread B calls the same method on the same 'wire' instance, but because the cachedWire is in-use, it does its own wire.clone(),
> making a shallow copy of wire's 'cachedWire'.
> 3) Only now does Thread A finish and call:     ((RuntimeWireImpl)wire).releaseWire();     (Nothing special happens here.  I'm just pointing out
> that since 2) happened first, the cached object was in-use and a new clone was made.
> 4) When Thread B gets to the end of RuntimeWireImpl.cloneAndBind() it calls:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> The net result is that the original wire has a ref, 'cachedWire' to the clone made in Thread B, which in turn has a ref to the clone made from Thread A.
> This illustrates the problem, as this can recursively grow unbounded.
> ---------
> A simple solution would seem to be to null out the 'cachedWire' field towards the end of RuntimeWireImpl.clone().   Maybe there's an even better one.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Resolved: (TUSCANY-2630) memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl

Posted by "Scott Kurz (JIRA)" <de...@tuscany.apache.org>.
     [ https://issues.apache.org/jira/browse/TUSCANY-2630?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Scott Kurz resolved TUSCANY-2630.
---------------------------------

       Resolution: Fixed
    Fix Version/s: Java-SCA-Next

> memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl
> ----------------------------------------------------------------------------
>
>                 Key: TUSCANY-2630
>                 URL: https://issues.apache.org/jira/browse/TUSCANY-2630
>             Project: Tuscany
>          Issue Type: Bug
>          Components: Java SCA Core Runtime
>            Reporter: Scott Kurz
>             Fix For: Java-SCA-Next
>
>
> We can end up with an unbounded chain of RuntimeWireImpls  because of the way the 'cachedWire' field is handled to cache a callback wire.
> The problem arises with a sequence like:
> 1) Thread A calls CallbackReferenceImpl.getCallbackWire(), which results in a wire.clone() and then the boundWire is "cached" via:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> 2) Thread B calls the same method on the same 'wire' instance, but because the cachedWire is in-use, it does its own wire.clone(),
> making a shallow copy of wire's 'cachedWire'.
> 3) Only now does Thread A finish and call:     ((RuntimeWireImpl)wire).releaseWire();     (Nothing special happens here.  I'm just pointing out
> that since 2) happened first, the cached object was in-use and a new clone was made.
> 4) When Thread B gets to the end of RuntimeWireImpl.cloneAndBind() it calls:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> The net result is that the original wire has a ref, 'cachedWire' to the clone made in Thread B, which in turn has a ref to the clone made from Thread A.
> This illustrates the problem, as this can recursively grow unbounded.
> ---------
> A simple solution would seem to be to null out the 'cachedWire' field towards the end of RuntimeWireImpl.clone().   Maybe there's an even better one.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (TUSCANY-2630) memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl

Posted by "ant elder (JIRA)" <de...@tuscany.apache.org>.
    [ https://issues.apache.org/jira/browse/TUSCANY-2630?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12637414#action_12637414 ] 

ant elder commented on TUSCANY-2630:
------------------------------------

The simple solution you propose looks ok to me but other than ensuring the build still works it would be hard for me to test as its quite a complicated scenario. Any chance you could provide a testcase demonstrating the issue? If its a lot of work to make your test contributable how about you just make the change locally yourself and confirm it fixes the leak in your environment?


> memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl
> ----------------------------------------------------------------------------
>
>                 Key: TUSCANY-2630
>                 URL: https://issues.apache.org/jira/browse/TUSCANY-2630
>             Project: Tuscany
>          Issue Type: Bug
>          Components: Java SCA Core Runtime
>            Reporter: Scott Kurz
>
> We can end up with an unbounded chain of RuntimeWireImpls  because of the way the 'cachedWire' field is handled to cache a callback wire.
> The problem arises with a sequence like:
> 1) Thread A calls CallbackReferenceImpl.getCallbackWire(), which results in a wire.clone() and then the boundWire is "cached" via:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> 2) Thread B calls the same method on the same 'wire' instance, but because the cachedWire is in-use, it does its own wire.clone(),
> making a shallow copy of wire's 'cachedWire'.
> 3) Only now does Thread A finish and call:     ((RuntimeWireImpl)wire).releaseWire();     (Nothing special happens here.  I'm just pointing out
> that since 2) happened first, the cached object was in-use and a new clone was made.
> 4) When Thread B gets to the end of RuntimeWireImpl.cloneAndBind() it calls:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> The net result is that the original wire has a ref, 'cachedWire' to the clone made in Thread B, which in turn has a ref to the clone made from Thread A.
> This illustrates the problem, as this can recursively grow unbounded.
> ---------
> A simple solution would seem to be to null out the 'cachedWire' field towards the end of RuntimeWireImpl.clone().   Maybe there's an even better one.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (TUSCANY-2630) memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl

Posted by "Scott Kurz (JIRA)" <de...@tuscany.apache.org>.
    [ https://issues.apache.org/jira/browse/TUSCANY-2630?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12637471#action_12637471 ] 

Scott Kurz commented on TUSCANY-2630:
-------------------------------------

Thanks for taking a look.   Not understanding this code real well, I have to take it for granted that we have a good reason for not sharing the callback wire across threads, (though I was half-wondering if that might have been an old assumption that someone might realize is no longer needed).  

I don't know how to contribute a test showing this timing-dependent issue;  I have to use the debugger to step through to recreate.  However, I would say I've confirmed this fixes the leak in my environment. 



> memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl
> ----------------------------------------------------------------------------
>
>                 Key: TUSCANY-2630
>                 URL: https://issues.apache.org/jira/browse/TUSCANY-2630
>             Project: Tuscany
>          Issue Type: Bug
>          Components: Java SCA Core Runtime
>            Reporter: Scott Kurz
>
> We can end up with an unbounded chain of RuntimeWireImpls  because of the way the 'cachedWire' field is handled to cache a callback wire.
> The problem arises with a sequence like:
> 1) Thread A calls CallbackReferenceImpl.getCallbackWire(), which results in a wire.clone() and then the boundWire is "cached" via:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> 2) Thread B calls the same method on the same 'wire' instance, but because the cachedWire is in-use, it does its own wire.clone(),
> making a shallow copy of wire's 'cachedWire'.
> 3) Only now does Thread A finish and call:     ((RuntimeWireImpl)wire).releaseWire();     (Nothing special happens here.  I'm just pointing out
> that since 2) happened first, the cached object was in-use and a new clone was made.
> 4) When Thread B gets to the end of RuntimeWireImpl.cloneAndBind() it calls:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> The net result is that the original wire has a ref, 'cachedWire' to the clone made in Thread B, which in turn has a ref to the clone made from Thread A.
> This illustrates the problem, as this can recursively grow unbounded.
> ---------
> A simple solution would seem to be to null out the 'cachedWire' field towards the end of RuntimeWireImpl.clone().   Maybe there's an even better one.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (TUSCANY-2630) memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl

Posted by "Simon Nash (JIRA)" <de...@tuscany.apache.org>.
    [ https://issues.apache.org/jira/browse/TUSCANY-2630?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12638098#action_12638098 ] 

Simon Nash commented on TUSCANY-2630:
-------------------------------------

Apologies for not considering the multi-threaded case when I wrote this caching code.  The fix seems fine.  Callback wires can't be shared between callback invocations because there is code in the callback path that modifies the wire and/or its contents.  The cache was intended to avoid the need to create a new clone on every callback invocation between the same pair of components.  It will be less effective in this multi-threaded case than in a single-threaded scenario, but it should still be better than not doing any caching.

> memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl
> ----------------------------------------------------------------------------
>
>                 Key: TUSCANY-2630
>                 URL: https://issues.apache.org/jira/browse/TUSCANY-2630
>             Project: Tuscany
>          Issue Type: Bug
>          Components: Java SCA Core Runtime
>            Reporter: Scott Kurz
>
> We can end up with an unbounded chain of RuntimeWireImpls  because of the way the 'cachedWire' field is handled to cache a callback wire.
> The problem arises with a sequence like:
> 1) Thread A calls CallbackReferenceImpl.getCallbackWire(), which results in a wire.clone() and then the boundWire is "cached" via:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> 2) Thread B calls the same method on the same 'wire' instance, but because the cachedWire is in-use, it does its own wire.clone(),
> making a shallow copy of wire's 'cachedWire'.
> 3) Only now does Thread A finish and call:     ((RuntimeWireImpl)wire).releaseWire();     (Nothing special happens here.  I'm just pointing out
> that since 2) happened first, the cached object was in-use and a new clone was made.
> 4) When Thread B gets to the end of RuntimeWireImpl.cloneAndBind() it calls:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> The net result is that the original wire has a ref, 'cachedWire' to the clone made in Thread B, which in turn has a ref to the clone made from Thread A.
> This illustrates the problem, as this can recursively grow unbounded.
> ---------
> A simple solution would seem to be to null out the 'cachedWire' field towards the end of RuntimeWireImpl.clone().   Maybe there's an even better one.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Updated: (TUSCANY-2630) memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl

Posted by "Simon Laws (JIRA)" <de...@tuscany.apache.org>.
     [ https://issues.apache.org/jira/browse/TUSCANY-2630?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Simon Laws updated TUSCANY-2630:
--------------------------------

    Fix Version/s:     (was: Java-SCA-Next)
                   Java SCA-1.3.3

I want to put this in 1.3.3 also in case it comes up

> memleak as RuntimeWireImpl callback cachedWire ref leaks due to clone() impl
> ----------------------------------------------------------------------------
>
>                 Key: TUSCANY-2630
>                 URL: https://issues.apache.org/jira/browse/TUSCANY-2630
>             Project: Tuscany
>          Issue Type: Bug
>          Components: Java SCA Core Runtime
>            Reporter: Scott Kurz
>             Fix For: Java SCA-1.3.3
>
>
> We can end up with an unbounded chain of RuntimeWireImpls  because of the way the 'cachedWire' field is handled to cache a callback wire.
> The problem arises with a sequence like:
> 1) Thread A calls CallbackReferenceImpl.getCallbackWire(), which results in a wire.clone() and then the boundWire is "cached" via:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> 2) Thread B calls the same method on the same 'wire' instance, but because the cachedWire is in-use, it does its own wire.clone(),
> making a shallow copy of wire's 'cachedWire'.
> 3) Only now does Thread A finish and call:     ((RuntimeWireImpl)wire).releaseWire();     (Nothing special happens here.  I'm just pointing out
> that since 2) happened first, the cached object was in-use and a new clone was made.
> 4) When Thread B gets to the end of RuntimeWireImpl.cloneAndBind() it calls:
>   ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
> The net result is that the original wire has a ref, 'cachedWire' to the clone made in Thread B, which in turn has a ref to the clone made from Thread A.
> This illustrates the problem, as this can recursively grow unbounded.
> ---------
> A simple solution would seem to be to null out the 'cachedWire' field towards the end of RuntimeWireImpl.clone().   Maybe there's an even better one.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.