<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://bugs.webkit.org/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4.1"
          urlbase="https://bugs.webkit.org/"
          
          maintainer="admin@webkit.org"
>

    <bug>
          <bug_id>204515</bug_id>
          
          <creation_ts>2019-11-22 07:50:31 -0800</creation_ts>
          <short_desc>WebKit doesn&apos;t garbage collect MessageEvent objects with transferables quickly enough</short_desc>
          <delta_ts>2020-06-04 12:12:40 -0700</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WebKit</product>
          <component>New Bugs</component>
          <version>Safari Technology Preview</version>
          <rep_platform>Unspecified</rep_platform>
          <op_sys>Unspecified</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>DUPLICATE</resolution>
          <dup_id>203990</dup_id>
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords>InRadar</keywords>
          <priority>P2</priority>
          <bug_severity>Normal</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Konstantin Kaefer">mail</reporter>
          <assigned_to name="Nobody">webkit-unassigned</assigned_to>
          <cc>cdumez</cc>
    
    <cc>webkit-bug-importer</cc>
    
    <cc>youennf</cc>
    
    <cc>ysuzuki</cc>
          

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>1592794</commentid>
    <comment_count>0</comment_count>
      <attachid>384152</attachid>
    <who name="Konstantin Kaefer">mail</who>
    <bug_when>2019-11-22 07:50:31 -0800</bug_when>
    <thetext>Created attachment 384152
postMessage with a long list of transferables

Over in the the Mapbox GL JS project, we&apos;ve seen severe memory growth in WebKit and have been tracking the issue on https://github.com/mapbox/mapbox-gl-js/issues/8771. Severe memory growth means that the page&apos;s process can quickly jump to more than a gigabyte of memory when continually loading tiles (e.g. panning or zooming).

We&apos;ve observed that this only happens when using web workers. We use web workers to load and process tiled map data for use with WebGL, then send it to the main thread. A typical tile can have up to a few hundred ArrayBuffers. We are using `postMessage` with an array of transferable objects to avoid buffer copies.

Furthermore, we&apos;ve observed that _disabling_ transferable objects mostly fixes the memory growth issue and the process stays at ~500-600 MB.

I&apos;ve dug in to find out why this happens:

When sending a message to another thread with `postMessage` (https://github.com/WebKit/webkit/blob/6a89f57fb9482c4f5afef8a863d7b0dc08ab7b94/Source/WebCore/workers/Worker.cpp#L133), WebKit creates a `SerializedScriptValue` object, passing in a list of transferable objects. The message gets serialized by the `CloneSerializer`, which adds indices to the ArrayBuffers stored directly in the `SerializedScriptValue` (https://github.com/WebKit/webkit/blob/6a89f57fb9482c4f5afef8a863d7b0dc08ab7b94/Source/WebCore/bindings/js/SerializedScriptValue.h#L120) object.

The message with the `SerializedScriptValue` gets pushed to the worker&apos;s or main thread&apos;s queue. Once the event get&apos;s dispatched (https://github.com/WebKit/webkit/blob/6a89f57fb9482c4f5afef8a863d7b0dc08ab7b94/Source/WebCore/workers/WorkerMessagingProxy.cpp#L120), a new `MessageEvent` object is created, which obtains ownership of the `SerializedScriptValue`.

WebKit doesn&apos;t seem to garbage collect `MessageEvent` objects frequently enough. I instrumented `SerializedScriptValue` and found that it can accumulate several thousand of those objects until GC kicks in, causing the process to allocate more and more memory. This means it&apos;s not technically a leak, but still causes excessive memory growth.



A few other observations:

The `MessageEvent` has to actually be dispatched into JS land. If there&apos;s no event listener, the `SerializedScriptValue`s get destructed immediately when the message is processed on the other thread. This means that the mere creation of a `MessageEvent` doesn&apos;t cause the leak.

Memory grows regardless of whether the value is ever _deserialized_. I rebuilt WebKit with deserialization disabled entirely and still observed the memory growth caused by WebKit hanging on to `MessageEvent` objects.

While the memory growth is impacted by the byte count of the transferred ArrayBuffers, the _number_ of elements in the transferables list has at least an equal effect. I created a small benchmark that allocates zero-size ArrayBuffer, then adds the same object 8192 times to the list of transferables. This causes the vector allocated to hold the ArrayBufferContent objects to become pretty large even if all of its members are zero because WebKit filters duplicates.

When attaching a smallish ArrayBuffer to the `MessageEvent` object when it is _received_ by just executing `event.foo = new ArrayBuffer(32768)`, I was able to trigger GC of those `MessageEvent` objects much more frequently, mitigating the memory growth somewhat. This leads me to believe that GC isn&apos;t aware of the actual size of `MessageEvent` objects. It should be a combination of the byte size of the stored ArrayBuffers and the count of them.

I&apos;ve used the GC Heap Inspector and it looks like the `MessageEvent` objects aren&apos;t referenced from a GC root.

The direction of transfer (worker → main, or main → worker) doesn&apos;t seem to matter for how frequently they are GCed.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>1593055</commentid>
    <comment_count>1</comment_count>
    <who name="Radar WebKit Bug Importer">webkit-bug-importer</who>
    <bug_when>2019-11-22 15:17:51 -0800</bug_when>
    <thetext>&lt;rdar://problem/57442706&gt;</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>1659239</commentid>
    <comment_count>2</comment_count>
    <who name="Yusuke Suzuki">ysuzuki</who>
    <bug_when>2020-06-04 12:12:40 -0700</bug_when>
    <thetext>

*** This bug has been marked as a duplicate of bug 203990 ***</thetext>
  </long_desc>
      
          <attachment
              isobsolete="0"
              ispatch="0"
              isprivate="0"
          >
            <attachid>384152</attachid>
            <date>2019-11-22 07:50:31 -0800</date>
            <delta_ts>2019-11-22 07:50:31 -0800</delta_ts>
            <desc>postMessage with a long list of transferables</desc>
            <filename>long-transferable-list-leak-worker.html</filename>
            <type>text/html</type>
            <size>601</size>
            <attacher name="Konstantin Kaefer">mail</attacher>
            
              <data encoding="base64">PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8aGVhZD4KICAgIDxtZXRhIGNoYXJzZXQ9J3V0Zi04JyAv
PgogICAgPHRpdGxlPkxvbmcgVHJhbnNmZXJhYmxlcyBMaXN0PC90aXRsZT4KPC9oZWFkPgo8Ym9k
eT4KCjxzY3JpcHQ+Cgpjb25zdCB3b3JrZXIgPSBuZXcgV29ya2VyKFVSTC5jcmVhdGVPYmplY3RV
UkwobmV3IEJsb2IoW2AKCm9ubWVzc2FnZSA9IGV2ZW50ID0+IHsKICAgIC8vIE5lZWRlZCB0byBw
cmV2ZW50IGh0dHBzOi8vYnVncy53ZWJraXQub3JnL3Nob3dfYnVnLmNnaT9pZD0yMDM5OTAKICAg
IGV2ZW50LmRhdGE7Cn07CgpgXSwgeyB0eXBlOiAnYXBwbGljYXRpb24vamF2YXNjcmlwdCcgfSkp
KTsKCnNldEludGVydmFsKCgpID0+IHsKICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBBcnJheUJ1ZmZl
cigwKTsKCiAgICBjb25zdCB0cmFuc2ZlcmFibGVzID0gW107CiAgICBmb3IgKGxldCBpID0gMDsg
aSA8IDgxOTI7ICsraSkgewogICAgICAgIHRyYW5zZmVyYWJsZXMucHVzaChidWZmZXIpOwogICAg
fQoKICAgIHdvcmtlci5wb3N0TWVzc2FnZSh7YnVmZmVyfSwgdHJhbnNmZXJhYmxlcyk7Cn0sIDEw
KTsKCjwvc2NyaXB0PgoKPC9ib2R5Pgo8L2h0bWw+Cg==
</data>

          </attachment>
      

    </bug>

</bugzilla>