使用 Web Workers(垃圾收集器)可能出现内存泄漏

发布于 2024-12-04 14:50:52 字数 1119 浏览 0 评论 0原文

我有一个应用程序,它在单击按钮后调用网络工作人员。计算被转移到工作线程以减轻 UI 负担,并使其在计算时响应用户操作。

一切顺利,大约 0.8-1.5 秒后,工作人员发送响应。在 worker.onmessage 中,我执行了所有需要的 DOM 操作,但在此垃圾收集器出现之后,实际上会阻塞 UI 2 秒或更长时间,具体取决于 CPU。这真的让我很困惑,因为 UI 阻塞正是我想要防止的。

这是时间线/内存控制台选项卡的屏幕截图:

如您所见,垃圾收集器事件在所有 DOM 操作之后发生。实际上只有一个重绘事件(使用了DocumentFragment)。

主要js代码:

var sortWorker = new Worker('js/contactsorter.js');
sortWorker.onmessage = function(e) {
    var messages = [];
    e.data.forEach(function(userDoc) {
        var contactSection = _drawContact(userDoc);
        messages.push(contactSection);
    });
    
    meta.append(messages); // this actually appends document fragment as a child
};

sortWorker.postMessage(postMessageData);

contactsorter.js(worker):

onmessage = function(e) {
    var uid, output = [], usersStat = {};

    // calculations...
    
    postMessage(output);
    close();
};

有没有办法避免这个地方的这些垃圾收集器事件?

UPD:在我看来,垃圾收集器事件时间取决于发送给工作人员的数据量。
UPD2:关闭和启动后,垃圾收集器事件仅发生两次,因此阻塞 UI 的时间不到一秒。嗯?

I have an app which calls web worker after the button click. The calculations are moved to worker to relieve UI and make it responsive to user actions while calculations are being made.

Everything goes okay and after about 0.8-1.5s the worker sends a response. In worker.onmessage I perform all the needed DOM actions, but after this Garbage Collector appears and practically blocks the UI for 2 or more seconds depending on CPU. This is really confusing me, because UI blocking is what I want to prevent.

Here's the screenshot of timeline/memory console tab:

As you can see Garbage Collector events happen just after all DOM manipulations. Actually there's only one repaint event (DocumentFragment is used).

Main js code:

var sortWorker = new Worker('js/contactsorter.js');
sortWorker.onmessage = function(e) {
    var messages = [];
    e.data.forEach(function(userDoc) {
        var contactSection = _drawContact(userDoc);
        messages.push(contactSection);
    });
    
    meta.append(messages); // this actually appends document fragment as a child
};

sortWorker.postMessage(postMessageData);

contactsorter.js (worker):

onmessage = function(e) {
    var uid, output = [], usersStat = {};

    // calculations...
    
    postMessage(output);
    close();
};

Is there any way to avoid these Garbage Collector events in this place or not?

UPD: it seems to me that Garbage Collector event(s) time depends on data amount that was sent to worker.
UPD2: After shutdown and boot Garbage Collector events happen only twice thus blocking UI for less than a second. Hm?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

凉世弥音 2024-12-11 14:50:52

对于 Web Workers 需要记住的一件事是,当您将对象发送给工作人员时,您正在克隆该对象,尤其是当您在示例中使用它们时。因此,让我们用一个愚蠢的例子来运行一下:

  1. 制作大对象(你在评论中说 2M...wtf...哇) - 在主线程中分配 2M
  2. 发布到工作线程,主线程中仍然有 2M,加上创建的任何额外内容作为主线程中的绒毛来 JSONify 你的对象/数组,然后转到工作线程,工作线程中的 2M 是的,
  3. 在工作线程中的那个傻瓜上 Chug...这里主线程中的 2M+ 只是坐在等待 GC,现在可能会发生,可能不是...GC 在一定数量的新一代对象达到阈值后触发...比如在创建大量新对象和 dom 元素之后或期间:D
  4. Worker 回复一条消息,让我们假设 2M,即现在在主线程中重新创建了一个新的 2M(是的),加上 de JSONify 对象所需的任何绒毛内存对象......你知道这是怎么回事。

既然你说这是一个 chrome 应用程序(另一条评论),那么也许你可以重组你的代码以利用 可传输对象避免克隆创建临时对象当然,要使用可传输对象,您必须将其重组为数组缓冲区,这本身就是一个黑暗魔法。

One thing to remember with Web Workers, and especially as you have them used in your example, is that you are cloning the object when you send it over to the worker. So lets run through this with a silly example:

  1. Make big object (you said 2M in a comment... wtf... wow) - 2M allocated in main thread
  2. Post to worker, 2M in main thread still, plus whatever extra was created as fluff in the main thread to JSONify your object/array, then off to worker where 2M in worker yay
  3. Chug on that sucker in worker... here the 2M+ in the main thread is just sitting around waiting to GC, might happen now, might not... the GC triggers after a certain amount of new generation objects hit threshold... like say after or during the creation of a ton of new objects and dom elements :D
  4. Worker responds back with a message, lets assume 2M which is now made anew in the main thread for a new 2M (yay), plus whatever fluff memory objects required to de JSONify the object... you see where this is going.

Since you said that this was a chrome app (another comment), then maybe you can restructure your code to make use of Transferable Objects to avoid the object Cloning creation of temporary objects etc. Course, to use transferable objects you'd have to restructure as an array buffer and that's a dark magic all of itself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文