New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 751159 link

Starred by 3 users

Issue metadata

Status: Duplicate
Merged: issue 339480
Owner:
Closed: Sep 2017
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Windows
Pri: 3
Type: Bug-Regression



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 description

UserAgent: 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.
 
index.html
460 bytes View Download
server.js
1.3 KB View Download
Cc: erikc...@chromium.org etienneb@chromium.org
Labels: Performance-Memory
Labels: Needs-Triage-M60

Comment 4 by ricea@chromium.org, Aug 14 2017

Components: Blink>Network>WebSockets

Comment 5 by ricea@chromium.org, Aug 14 2017

Labels: -Type-Bug -Pri-2 Pri-3 Type-Bug-Regression
Owner: ricea@chromium.org
Status: Assigned (was: Unconfirmed)
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.

Comment 6 by ricea@chromium.org, 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.

Comment 7 by ricea@chromium.org, Aug 14 2017

Labels: OS-Linux
Owner: yhirano@chromium.org
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.
Cc: yukishiino@chromium.org
Components: Blink>Bindings
It is similar to  issue 749482 . yukishiino@, can you take a look?
Cc: keishi@chromium.org
Components: Blink>MemoryAllocator>GarbageCollection
+keishi@ as a GC expert.
Cc: -yukishiino@chromium.org yhirano@chromium.org
Owner: yukishiino@chromium.org
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.
Cc: haraken@chromium.org
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.

Cc: tyoshino@chromium.org
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.


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.

Mergedinto: 339480
Status: Duplicate (was: Assigned)

Sign in to add a comment