Process memory continues to increase when recycling a large number of DOM elements
Reported by
p.m.g.me...@gmail.com,
Apr 1 2017
|
||||||||||||||||||
Issue descriptionUserAgent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 Steps to reproduce the problem: 1. Open attached html in a new Chrome tab 2. Open Task Manager 3. Observe tab's process memory value going up What is the expected behavior? Have the process memory being freed just like is observed when doing the same evaluation in the previous Chrome stable 56.0.2924.87. What went wrong? Process memory is not being freed. The memory continues going up until the tab is killed. Element#innerHTML call should make the child elements to be garbage collected at some point. But it doesn't. Did this work before? Yes 56.0.2924.87 Does this work in other browsers? Yes Chrome version: 57.0.2987.133 Channel: stable OS Version: 7 Flash Version:
,
Apr 2 2017
Also reproducible in Windos Server 2008, Linux debian based distros - Ubuntu and Linux Mint - and Mac OS X.
,
Apr 2 2017
,
Apr 5 2017
Also reproducible on Suse Leap 4.2
,
Apr 5 2017
The original attached file (chrome-57-memory-leak-test-jquery-html.html) is using jQuery's .append().
The one attached here (chrome57-leak.html) is a much more simplified version of what jQuery's .append is doing, and it uses pure DOM instead of jQuery.
The key is the line `elem.getElementsByTagName('script' || '*');`. Removing that gets rid of the leak.
,
Apr 5 2017
That document fragment is causing many memory leaks across various contexts. :( (Or two ;))
,
Apr 6 2017
Sounds like cache for getElementsByTagName() isn't collected.
,
Apr 7 2017
I tried bisect-builds.py and found that the range is between 439853 (known good) and 439866 (known bad). This is same as issue 701601, so this is quite probably the issue with introducing TraceWrapper. The difference is, that the fix for 701601 should be in for M58 and M59, but this issue still reproduces on ToT build. Adding Blink>Javascript.
,
Apr 7 2017
,
Apr 7 2017
Attaching my accelerated version of the repro script (original one is in comment#5). This replaces span with <input> (which uses more memory per node) and repeat in 0.1sec (originally 1sec).
,
Apr 7 2017
Michael, could you take a look?
,
Apr 7 2017
Issue 609137 may be another instance of this. I suggest you write a C++ version of this in a unit test and see if you can cause a leak without JavaScript.
,
Apr 7 2017
Keishi-san, could you take a stab at this? This looks like more of an Oilpan issue, rather than V8's GC.
,
Apr 7 2017
Adding people interested in this issue in cc list.
,
Apr 7 2017
Looks like a wrapper tracing issue. Assigning to mlippautz I was able to reduce the test down to https://codereview.chromium.org/2805813003 The problem seems to be that live HTMLCollections is leaking. According to devtools memory panel the retainer is HTMLDocument. I don't know how trace wrapper works but I am suspecting that somehow Document::m_nodeLists's WeakMembers are traced as strong references in traceWrapper, which retains HTMLCollection wrapper, which retains HTMLCollection, which means it doesn't get removed from Document::m_nodeLists.
,
Apr 7 2017
Thanks for the analysis, I'll follow up as soon as I have some cycles.
,
Apr 7 2017
,
Apr 7 2017
Keishi, your analysis looks correct. Wrapper tracing only knows about strong references, and we definitely trace Document::m_nodeLists [1] haraken,jochen: Can you provide some guidance here? We usually try to avoid tracing references that are only held weakly in Oilpan, but this one was in before I started working on the project, so I guess there was a reason to do so. [1]: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/dom/Document.cpp?q=Document.cpp&sq=package:chromium&dr&l=6592
,
Apr 8 2017
Looks like the tracing was added in https://chromium.googlesource.com/chromium/src/+/a43e2359d03497a2a8a7e8327470abcf18eaa7d0 But I don't see how we would want to trace Document::m_nodeLists. They aren't JS exposed. Could we just delete it like https://codereview.chromium.org/2803313003 +haraken
,
Apr 8 2017
The following tests failed when we don't trace Document::m_nodeLists fast/dom/NodeList/nodelist-reachable.html fast/dom/gc-9.html fast/dom/htmlallcollection-reachable.html fast/dom/htmlcollection-reachable.html I can't find it written in the spec but it looks like we need to keep the LiveNodeList wrappers alive as long as the LiveNodeList::rootNode() element is alive. I think the LiveNodeList::rootNode() should retain the LiveNodeList, and the LiveNodeList should retain its wrapper. But I can't figure out how to express that in TraceWrapper.
,
Apr 9 2017
Yes. If we call: node.getElementsByTagName(); then we need to keep alive the node list while the node is alive. In other words, we need to trace from the node to the node list (*). The problem is that we don't have a trivial reference from the node to the node list. That's why we're (intentionally) doing something tricky; i.e., strongly trace Document::m_nodeLists. I'm a bit confused but is the node list really leaking? If we want to realize the behavior (*), we need to keep alive the node list while the node is alive. It's expected that the node list doesn't get collected until the node gets collected. Another option would be to change the behavior (*). How do other browsers behave?
,
Apr 9 2017
Looks like Firefox does not leak. Also Chrome didn't leak either prior to trace wrapper.
,
Apr 9 2017
Would it be possible to instead have a weak callback (on Document) magically do some incremental wrapper tracing of the live NodeLists?
,
Apr 9 2017
Let me ask the probably naive question here: Since m_nodeLists are weak for Oilpan anyways, what prohibits us from having a vector of wrapper tracing references on the actual nodes pointing to the corresponding node lists? Ideally we would converge to a solution where the object graph is properly set up so regular parent/child relationships determine liveness.
,
Apr 10 2017
#24: That's a very good question. Sigbjorn: Do you know why we don't have a HeapMember<LiveNodeList> on NodeRareData? Then we can simply trace the node list without relying on the weak member on Document.
,
Apr 10 2017
I think NodeLists are already owned by NodeListsNodeData, which is a part of NodeRareData. Document::node_lists_ is used for DOMTreeVersion invalidation.
,
Apr 10 2017
I now understand that it is wrong to wrapper-trace the node list from the document. If we do that, we end up with keeping the node list alive as long as the document is alive, not the node is alive. (i.e., even if we remove the node, the node list will be kept alive as long as the document is alive.) This leaks memory. So, yes, we should wrapper-trace the node list from the node. > I think NodeLists are already owned by NodeListsNodeData, which is a part of NodeRareData. Thanks. Yeah, it makes more sense to trace NodeListsNodeData::child_node_list_. By the way, do you know why NodeListsNodeData::child_node_list_ are weak members?
,
Apr 10 2017
Do we already wrapper trace the WeakMember NodeListsNodeData::child_node_list_ as strong? https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/dom/NodeListsNodeData.cpp?rcl=f3e971b60293bb5f7e6bd8de03b7f3ea77a2be13&l=53
,
Apr 11 2017
Yes we trace in NodeListsNodeData and as far as I understand it this should be enough. I would add some debugging information and check why we need to trace the node lists on the document. I am not sure I will get to this issue this week though as we have a short week here (holiday) and I have other non-arguable deadlines coming up.
,
Apr 11 2017
> Yes we trace in NodeListsNodeData and as far as I understand it this should be enough. I would add some debugging information and check why we need to trace the node lists on the document. Sounds good to me!
,
Apr 11 2017
Quick update: I had a look and we indeed seem to hold unnecessary HTMLCollection and LiveNodeList alive. The question now is how to avoid tracing through Document but rather trace through the Node. NodeListsNodeData::child_node_list_ is just the list of children (as the name suggests). We have two more cashes though in NodeListsNodeData which are atomic_name_caches_ and tag_collection_cache_ns_. Will now have a look at those.
,
Apr 11 2017
The problem seems to be indeed that we only trace wrappers for a subset of the lists on NodeListsNodeData. Potentialy fix is in https://codereview.chromium.org/2809183003/ - I checked against the first two tests that were failing and they pass. - I also checked against the minimized example. We hover somewhere around 40M of JS memory, depending on GC timing.
,
Apr 11 2017
,
Apr 12 2017
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/76798dbd04a30a8e1acdf71ecab93d09dac4ec5b commit 76798dbd04a30a8e1acdf71ecab93d09dac4ec5b Author: mlippautz <mlippautz@chromium.org> Date: Wed Apr 12 10:39:53 2017 [wrapper-tracing] Fix node list leak Only trace node lists that hang of live nodes. BUG= chromium:707544 Review-Url: https://codereview.chromium.org/2809183003 Cr-Commit-Position: refs/heads/master@{#463986} [modify] https://crrev.com/76798dbd04a30a8e1acdf71ecab93d09dac4ec5b/third_party/WebKit/Source/core/dom/Document.cpp [modify] https://crrev.com/76798dbd04a30a8e1acdf71ecab93d09dac4ec5b/third_party/WebKit/Source/core/dom/NodeListsNodeData.cpp [modify] https://crrev.com/76798dbd04a30a8e1acdf71ecab93d09dac4ec5b/third_party/WebKit/Source/core/dom/NodeListsNodeData.h
,
Apr 12 2017
This should be fixed now and merged back to M58 once backed into Canary.
,
Apr 13 2017
Your change meets the bar and is auto-approved for M58. Please go ahead and merge the CL to branch 3029 manually. Please contact milestone owner if you have questions. Owners: amineer@(Android), cmasso@(iOS), bhthompson@(ChromeOS), govind@(Desktop) For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Apr 13 2017
How can I identify the M58 snapshots containing this fix? https://storage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Win/
,
Apr 13 2017
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/fb5051f1e67383a98cf36b21f7cf78a9a44e6301 commit fb5051f1e67383a98cf36b21f7cf78a9a44e6301 Author: Michael Lippautz <mlippautz@chromium.org> Date: Thu Apr 13 11:34:41 2017 [wrapper-tracing] Fix node list leak Only trace node lists that hang of live nodes. BUG= chromium:707544 Review-Url: https://codereview.chromium.org/2809183003 Cr-Commit-Position: refs/heads/master@{#463986} (cherry picked from commit 76798dbd04a30a8e1acdf71ecab93d09dac4ec5b) Review-Url: https://codereview.chromium.org/2810253003 . Cr-Commit-Position: refs/branch-heads/3029@{#690} Cr-Branched-From: 939b32ee5ba05c396eef3fd992822fcca9a2e262-refs/heads/master@{#454471} [modify] https://crrev.com/fb5051f1e67383a98cf36b21f7cf78a9a44e6301/third_party/WebKit/Source/core/dom/Document.cpp [modify] https://crrev.com/fb5051f1e67383a98cf36b21f7cf78a9a44e6301/third_party/WebKit/Source/core/dom/NodeListsNodeData.cpp [modify] https://crrev.com/fb5051f1e67383a98cf36b21f7cf78a9a44e6301/third_party/WebKit/Source/core/dom/NodeListsNodeData.h
,
Apr 13 2017
"How can I identify the M58 snapshots containing this fix? https://storage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Win/" LAST_CHANGE -> 464386
,
Apr 18 2017
Issue 711448 has been merged into this issue.
,
Apr 19 2017
Tested the issue on windows 7, Ubuntu 14.04 and Mac 10.12.3 using chrome version 58.0.3029.81 with the below steps 1.Opened the attached chrome57-leak.html from comment #10. 2.Opened task manager 3.Observed memory increases and again freed which is not observed in M57. Please find the attached screen cast for the reference. Adding TE-Verified labels. Thanks,
,
Apr 19 2017
Issue 704546 has been merged into this issue.
,
Apr 19 2017
This was reported in M57 - should we merge it back there too?
,
Apr 19 2017
#44 - Chrome 58 is a few days away, so Chrome 57 will not go to the public at this point.
,
Apr 19 2017
|
||||||||||||||||||
►
Sign in to add a comment |
||||||||||||||||||
Comment 1 by phistuck@chromium.org
, Apr 2 2017Labels: -Pri-2 Performance-Memory Stability-Memory Pri-1
Status: Untriaged (was: Unconfirmed)