2021.5.6日报:修复mb v8 7.5的GC的bug

现在虽然把mb的v8版本升级到了7.5.但这玩意目前发现有个重大的小问题:https://element.eleme.cn/#/zh-CN/component/button这里面的按钮,过了几分钟就点不动了。

也就是没响应消息了。

调试了一番后,发现是如下这段代码就可以重现:

<script>
  var timerFunc;
  //var port1;
  function flushCallbacks () {
    console.log("flushCallbacks");
  }
  
  function initTimer() {
    var messageChannel = new MessageChannel;
    var port2 = messageChannel.port2;
    //port1 = messageChannel.port1;
    
    messageChannel.port1.onmessage = flushCallbacks;
    
    timerFunc = function() {
      console.log("postMessage"); // weolar
      port2.postMessage(1);
    }
  }
  initTimer();
  timerFunc();
</script>

在7.5v8中,会发现port1过不久就被析构了。

那为啥低版本v8不会呢?

对比了下新版本chromium,我看的是一头雾水。新版本chromium的gc比老版本复杂多了。貌似引入多代GC的概念。

只看到blink里有什么地方引用了这个port1..具体来说,是ThreadHeap::AdvanceMarking的marking_worklist_引用了。但这个marking_worklist_又是如何判断是否引入,我还没搞明白。

再看回老版本blink,终于发现了一点眉目。老版本blink,在MajorGCWrapperVisitor的VisitPersistentHandle,会遍历到这个port1.而这个遍历,是v8发起的,也是v8提到了变量。

整理了一下思路,大概搞明白了。v8对于这种native端的变量,会询问blink层。而blink层发现这玩意是个ActiveDOMObject对象,就会判断activeDOMObject->hasPendingActivity()。

老版本v8,我猜测是用m_isolate->SetObjectGroupId(*value, liveRootId());标识了这个对象在v8层不能被回收。然后到了gc的另外个阶段,也就是V8GCController::traceDOMWrappers这里面后,

v8会通知blink这个对象要做trace,也就是让blink不要回收。

而新版本v8,需要手动再调用tracer->RegisterEmbedderReference(tracedGlobal.Get());告诉v8.

我加上这个tracer->RegisterEmbedderReference(tracedGlobal.Get());后,貌似问题解决了。

上一篇:监控结果分析文件中网络分析NetWork(网络带宽占用计算)


下一篇:1、QT基础——Qt概述