Issue metadata
Sign in to add a comment
|
Continuously sending larger amounts of data (5 - 10 MB or more) over a WebSocket connection causes Chrome to use up a lot of memory and eventually crash.
Reported by
cristian...@gmail.com,
Aug 1 2017
|
||||||||||||||||||||||||
Issue descriptionUserAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 Steps to reproduce the problem: 1. Run node server.js (note this requires nodejs with the nodejs-websocket package) 2. Run index.html or point browser to http://127.0.0.1:8080/ The client should now be sending consecutive WebSocket messages to the server, and the server should be sending responses of the size specified in server.js 3. Use Task Manager or something similar to see the memory usage of Chrome; in my case, this slowly goes up towards 4GB (especially when the response size is larger than 10MB) and Chrome eventually runs out of memory What is the expected behavior? I have also tested this script with Firefox, Edge and Internet Explorer. In all of these browsers, the WebSocket data received from the server appears to get garbage collected frequently, and memory usage does not go above 250 MB or so. What went wrong? When running the script in Chrome, there appears to be a memory leak which causes it to hold on to the data received via WebSocket until Chrome runs out of memory. Garbage collection appears to happen occasionally, but it is not enough to keep it running smoothly or to prevent it from crashing. Did this work before? No Does this work in other browsers? Yes Chrome version: 60.0.3112.78 Channel: stable OS Version: 10.0 Flash Version: While the example above is for a Node.js server, I have tried something similar with a C++ WinHttp-based WebSocket server, and I encountered the same issue in Chrome.
,
Aug 2 2017
,
Aug 2 2017
,
Aug 14 2017
,
Aug 14 2017
I bisected the issue. Output: You are probably looking for a change made after 167864 (known good), but no later than 167872 (first known bad). CHANGELOG URL: https://chromium.googlesource.com/chromium/src/+log/4ceb5c2d2087a23e5629427b398cc71f35b04287..67d13d556a713a64e41c2ff76f58f4839296f37e This result may be bogus, as there's no obvious culprit in that range.
,
Aug 14 2017
Yes, the result was bogus. I needed the --no-sandbox flag for older versions to stop the renderer from crashing at startup. I haven't succeeded in bisecting because the regression happened a long time ago and many other bugs have existed in various versions which stop the repro from working. There definitely were versions that worked.
,
Aug 14 2017
Incidentally, garbage collection does free the memory when it happens (as long as DevTools is not open). But it doesn't trigger until several GB has been allocated, which is enough to crash most machines. I have been using ulimit -v 2000000 for testing as this causes the crash to happen reasonably quickly, and also avoids the OOM killer taking out other processes. Assigning to yhirano who knows more about the interaction between GC and WebSockets.
,
Aug 15 2017
It is similar to issue 749482 . yukishiino@, can you take a look?
,
Aug 15 2017
+keishi@ as a GC expert.
,
Aug 16 2017
This is similar to issue 339480 which was fixed as https://src.chromium.org/viewvc/blink?view=revision&revision=166825. The code is deleted by https://codereview.chromium.org/531183003.
,
Sep 1 2017
As far as I investigated, blink::MessageEvent is consuming memory without reporting it to V8, hence V8 GC doesn't get scheduled. The repro case doesn't use ArrayBuffer. The message data is stored in blink::MessageEvent::data_as_string_ of type WTFString, and the memory usage is not reported to V8. The situation looks quite similar to Issue 749482 . The common pattern is that Blink stores data internally without telling it to V8, and converts Blink-internal data to V8 representation lazily when accessed. The repro cases never touches the data so there is no chance to report the memory usage to V8 nor increase the memory usage of V8 heap.
,
Sep 2 2017
Thanks for digging! Would it be possible to report the size of MessageEvent::data_as_string_ to V8 even before the MessageEvent is touched by V8? The point is that if some memory cannot be released without triggering a V8 GC, the memory should be reported to V8. Whether V8 has touched the data or not does not really matter.
,
Sep 4 2017
Another option is to convert the WTFString to a v8::String and store it in data_as_string_ (i.e. change the type of data_as_string_ from WTFString to v8::String) and use wrapper-tracing to make the v8::String alive. Then, V8 will be aware of the memory usage. Since v8::String is NOT v8::Context-aware, it's not so dangerous.
,
Sep 5 2017
|
|||||||||||||||||||||||||
►
Sign in to add a comment |
|||||||||||||||||||||||||
Comment 1 by etienneb@chromium.org
, Aug 2 2017