Opened 10 years ago
Closed 10 years ago
#13904 closed bug (notabug)
"on" events leak memory in the checkContext variable
Reported by: | Owned by: | ||
---|---|---|---|
Priority: | undecided | Milestone: | None |
Component: | unfiled | Version: | 1.9.1 |
Keywords: | Cc: | gibson042, Timmy Willison | |
Blocked by: | Blocking: |
Description
I've created a small sample which shows how the "on" function can leak memory. This was tested in Chrome 26, looking at the Memory Heap. To reproduce:
1) Load this test page (I've not used jsFiddle as it has it's own leaks and confuses the situation).
<html> <head> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script> </head> <body> <div class="i_will_leak"> <input type="text" /> </div> <button>Leak</button> <script> $(function () { $('div').on('click', 'input', function () { this.value = 'clicked'; }) $('button').click(function () { $('div').off().unbind().remove(); }) }); </script> </body> </html>
2) Click on the input box 3) Click the "Leak" button. This simply removes all events and trashes the element. (I've purposefully called all the removes I can think of, although remove() should suffice) 4) Check the memory profile for detached nodes and the "i_will_leak" DIV will have leaked against the checkContext variable.
NOTE: This ONLY happens if you actually click the input box, if you don't interact with it, then it doesn't leak. Hence the issue is in dispatching the event, rather than attaching or removing it.
Expected Result: It shouldn't leak
I hope this is enough information.
Change History (7)
comment:1 Changed 10 years ago by
Owner: | set to [email protected]… |
---|---|
Status: | new → pending |
comment:2 Changed 10 years ago by
Status: | pending → new |
---|
I don't believe it is as I've not seen it go away. Unless you have examples of how a subsequent query clears the cache? Surely if I've removed the event and node there is noting left to cache?
comment:3 Changed 10 years ago by
Status: | new → pending |
---|
It won't go away, but it also shouldn't happen a second time. You've cached a selector there.
My question, restated, is: Does it "leak" every time you run that, or only the first time? You'll need to redo your example to allow you to re-attach the event handler.
comment:4 Changed 10 years ago by
Status: | pending → new |
---|
Hi, I'm not sure I follow 100%, but I've changed the sample to allow a recreation and does appear to leak only once. Please confirm this is correct:
<html> <head> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script> </head> <body> <div id="newAdd"> </div> <button id="leak">Leak</button> <button id="readd">Re-add</button> <script> function buildSample() { $('#newAdd').append('<div class="i_will_leak"><input type="text" /></div>'); $('.i_will_leak').on('click', 'input', function () { this.value = 'clicked'; }) } $(function () { $('#leak').click(function () { $('.i_will_leak').off().unbind().remove(); }) $('#readd').click(buildSample) buildSample(); }); </script> </body> </html>
Thanks.
comment:5 Changed 10 years ago by
Cc: | gibson042 Timmy Willison added |
---|
We're caching a reference to the selector the first time we see it, so that we don't need to recompute it each time it's used. This is not a leak, we still have and in the future will use the reference to the code used to compute the 'input' selector string when needed.
timmywil, gibson042 am I misinterpreting this?
comment:6 Changed 10 years ago by
You've basically got it, dmethvin... as documented in the source:
The foundational matcher ensures that elements are reachable from top-level context(s)
We store a reference to the context and then test it with one of two functions (based on whether context is a node or an array). This allows us to use the same code when searching subtrees as we do with entire documents.
comment:7 Changed 10 years ago by
Resolution: | → notabug |
---|---|
Status: | new → closed |
Okay, that's what I thought.
It's just caching the selector there I think, we don't attempt to removed cached selectors because they can be reused. Or are you saying this continues without bound?