最后的结论很简单,是我绑定v8 function的时候没释放。但查找问题的过程比较艰难,因为

v8的代码实在太难读了。

下面先大概了解下v8的垃圾回收机制。

v8\src\global-handles.cc里有个GlobalHandles类,管理了所有使用v8::Persistent<XXX>形式声明的永久性

v8变量。说永久性的意思是,除非自己主动调用v8::Persistent::reset,不然就一直占稳不释放了。

但有个例外,就是v8::Persistent::SetWeak形式设置了释放回调,或者叫弱回调(这里有点存疑)。

看段堆栈:

        node.dll!v8::internal::GlobalHandles::NodeBlock::IncreaseUses  C++node.dll!v8::internal::GlobalHandles::Node::IncreaseBlockUses  C++node.dll!v8::internal::GlobalHandles::Node::Acquire    C++node.dll!v8::internal::GlobalHandles::Create   C++node.dll!v8::V8::GlobalizeReference    C++node.dll!v8::PersistentBase<v8::ObjectTemplate>::New C++
>    node.dll!v8::PersistentBase<v8::ObjectTemplate>::Reset<v8::ObjectTemplate>  C++node.dll!blink::V8Window::getShadowObjectTemplate  C++node.dll!blink::WindowProxy::createContext C++node.dll!blink::WindowProxy::initialize    C++node.dll!blink::WindowProxy::initializeIfNeeded    C++node.dll!blink::ScriptController::windowProxy  C++node.dll!blink::LocalFrame::windowProxy    C++node.dll!blink::toV8ContextEvenIfDetached  C++node.dll!blink::ScriptState::forWorld  C++node.dll!blink::ScriptState::forMainWorld  C++node.dll!blink::WebLocalFrameImpl::mainWorldScriptContext  C++node.dll!wke::CWebView::globalExec C++node.dll!wkeGlobalExec C++wkexe.exe!handleDocumentReady  C++node.dll!wke::CWebWindow::_onDocumentReady C++node.dll!wke::CWebWindow::_staticOnDocumentReady   C++node.dll!content::WebFrameClientImpl::didFinishDocumentLoad    C++node.dll!blink::FrameLoaderClientImpl::dispatchDidFinishDocumentLoad   C++node.dll!blink::FrameLoader::finishedParsing   C++node.dll!blink::Document::finishedParsing  C++node.dll!blink::HTMLConstructionSite::finishedParsing  C++node.dll!blink::HTMLTreeBuilder::finished  C++node.dll!blink::HTMLDocumentParser::end    C++node.dll!blink::HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd  C++node.dll!blink::HTMLDocumentParser::prepareToStopParsing   C++node.dll!blink::HTMLDocumentParser::processParsedChunkFromBackgroundParser C++node.dll!blink::HTMLDocumentParser::pumpPendingSpeculations    C++node.dll!blink::HTMLDocumentParser::resumeParsingAfterYield    C++node.dll!blink::HTMLParserScheduler::continueParsing   C++node.dll!WTF::FunctionWrappernode.dll!WTF::PartBoundFunctionImplnode.dll!blink::CancellableTaskFactory::CancellableTask::run   C++node.dll!content::WebTimerBase::fired  C++node.dll!content::WebThreadImpl::schedulerTasks    C++node.dll!content::WebThreadImpl::fire  C++node.dll!wkeWake   C++wkexe.exe!RunMessageLoop   C++

这显示了如何把永久对象放到GlobalHandles里。

当垃圾回收的时刻到来时,

>   node.dll!v8::internal::GlobalHandles::IdentifyWeakHandles   C++node.dll!v8::internal::MarkCompactCollector::MarkLiveObjects   C++node.dll!v8::internal::MarkCompactCollector::CollectGarbage    C++node.dll!v8::internal::Heap::MarkCompact   C++node.dll!v8::internal::Heap::PerformGarbageCollection  C++node.dll!v8::internal::Heap::CollectGarbage    C++node.dll!v8::internal::Heap::CollectAllAvailableGarbage    C++node.dll!v8::Isolate::LowMemoryNotification    C++node.dll!content::BlinkPlatformImpl::doGarbageCollected    C++node.dll!content::BlinkPlatformImpl::garbageCollectedTimer C++node.dll!blink::Timer<content::BlinkPlatformImpl>::fired C++

可以看到GlobalHandles::IdentifyWeakHandles这里会遍历所有v8::Persistent永久化对象。

当设置了弱回调的时候,这些永久化对象就靠v8自己的垃圾处理机制了。此时就有个问题,v8如何知道这个对象无人引用了呢?

下面看几个v8的数据结构:

class GlobalHandles::Node

class Object

class  HeapObject

class Marking

要读懂垃圾回收机制,连得理清楚这几个对象的关系。

实际上是这样:

Object相对于对应js里的Object。不过注意下,v8分外部导出到头文件的Object和内部Object,这两货其实是一样的,只是

为了工程上的严谨性。

这个GlobalHandles::Node代表每个存在GlobalHandles里的对象,如上面那个持久化东西。Object也被存在这个node里。

但这里有个特别要强调的是,一个object可以放在多个 node。这点对后来解决内存泄漏比较关键。

每个object,其实是个以HeapObject开头的内存。这个HeapObject就是为了方便内存管理而设计的。

HeapObject的头部,通过一系列位运算,地址运算,得到了Marking对象。这过程我没怎么看懂,因为都是类似

static_cast<uint32_t>(addr - this->address()) >> kPointerSizeLog2;

这种风格的运算…实在不想搞明白算出真实Marking地址了。

总之得到Marking地址后,就可以通过Marking::IsBlack,Marking::IsWhite来判断Marking的状态(或者叫颜色)了。

black表示内存被占用,white表示内存没人占用。

(插一句,其实准确的说,应该是Marking里的cell类来记录这个颜色,不同object最后是在cell里标记的)

那问题来了,什么时候会去设置这些颜色呢?

最终是通过Marking::WhiteToBlack、Marking::MarkBlack来标记的。下个断点,

>   node.dll!v8::internal::Marking::WhiteToBlack    C++node.dll!v8::internal::MarkCompactCollector::MarkObject    C++node.dll!v8::internal::MarkCompactMarkingVisitor::MarkObjectByPointer  C++node.dll!v8::internal::MarkCompactMarkingVisitor::VisitPointers    C++node.dll!v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::VisitMap   C++node.dll!v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::IterateBody    C++node.dll!v8::internal::MarkCompactCollector::EmptyMarkingDeque C++node.dll!v8::internal::MarkCompactCollector::ProcessMarkingDeque   C++node.dll!v8::internal::MarkCompactCollector::PrepareForCodeFlushing    C++node.dll!v8::internal::MarkCompactCollector::MarkLiveObjects   C++node.dll!v8::internal::MarkCompactCollector::CollectGarbage    C++node.dll!v8::internal::Heap::MarkCompact   C++node.dll!v8::internal::Heap::PerformGarbageCollection  C++node.dll!v8::internal::Heap::CollectGarbage    C++node.dll!v8::internal::Heap::CollectAllAvailableGarbage    C++node.dll!v8::Isolate::LowMemoryNotification    C++node.dll!content::BlinkPlatformImpl::doGarbageCollected    C++

其实关键就是这句

v8::internal::MarkCompactMarkingVisitor::VisitPointers

v8构造了一个图结构,通过不停遍历里面的节点,如果访问到的节点,就标记为block。

那回到最上面的问题,

一个object可以放在多个 node。如果一个node没人引用了,会被标记为white。这是下面堆栈做的:

>   node.dll!v8::internal::Sweep<0,0,1,0> C++node.dll!v8::internal::MarkCompactCollector::SweepSpace    C++node.dll!v8::internal::MarkCompactCollector::SweepSpaces   C++node.dll!v8::internal::MarkCompactCollector::CollectGarbage    C++node.dll!v8::internal::Heap::MarkCompact   C++node.dll!v8::internal::Heap::PerformGarbageCollection  C++node.dll!v8::internal::Heap::CollectGarbage    C++node.dll!v8::internal::Heap::CollectAllAvailableGarbage    C++node.dll!v8::Isolate::LowMemoryNotification    C++

但如果一个object放在两个node呢?比如有两个v8::Persistent<Objcet>持有了这个object,那就是一个object放在两个node里。

当第一个node在v8::internal::Sweep<0,0,1,0>里被标记white时,

下面堆栈可能又因为另个node在引用这个object,而导致同样的Marking又被标记成black:

>   node.dll!v8::internal::MarkBit::Set()node.dll!v8::internal::Marking::WhiteToBlacknode.dll!v8::internal::MarkCompactCollector::SetMarknode.dll!v8::internal::RootMarkingVisitor::MarkObjectByPointernode.dll!v8::internal::RootMarkingVisitor::VisitPointernode.dll!v8::internal::GlobalHandles::IterateStrongRootsnode.dll!v8::internal::Heap::IterateStrongRootsnode.dll!v8::internal::MarkCompactCollector::MarkRootsnode.dll!v8::internal::MarkCompactCollector::MarkLiveObjectsnode.dll!v8::internal::MarkCompactCollector::CollectGarbagenode.dll!v8::internal::Heap::MarkCompactnode.dll!v8::internal::Heap::PerformGarbageCollectionnode.dll!v8::internal::Heap::CollectGarbagenode.dll!v8::internal::Heap::CollectAllAvailableGarbagenode.dll!v8::Isolate::LowMemoryNotificationnode.dll!content::BlinkPlatformImpl::doGarbageCollectednode.dll!content::BlinkPlatformImpl::garbageCollectedTimernode.dll!blink::Timer

最后跟踪到这里时,才发现miniblink是因为同个object被两个node引用导致没释放。问题解决。

修复miniblink一处内存泄漏的bug相关推荐

  1. 无处不在的内存泄漏-苹果BUG?

    即使你对自己的技术功底有再多的自信,都请养成使用Instruments工具排查内存泄漏的良好习惯, 即使Instruments再牛逼,你也还要养成看接口文档的良好习惯,因为你防谁也防不了苹果... 下 ...

  2. Android内存泄漏leakcanary2.7

    一.内存泄漏 1.1 内存泄漏简介   内存泄漏,是指一些对象已经不再需要,但是无法成功被gc回收,导致这部分内存无法释放,造成资源的浪费.当大量的内存泄漏堆积时,严重时还容易间接引发OOM.   例 ...

  3. “因为内存泄漏,我的 M1 MacBook Pro 瘫痪了”

    上个月,苹果在宣布"王炸候场中"后,19 号发布了 AirPods 3.HomePod mini 等新品,而这场发布会真正的主角当属新款 MacBook Pro:强悍的 M1 Pr ...

  4. java内存泄漏案例_寻找内存泄漏:一个案例研究

    java内存泄漏案例 一周前,我被要求修复一个有内存泄漏问题的webapp. 考虑到过去两年左右的时间里我已经看到并修复了数百个泄漏,我想这有多难. 但是事实证明这是一个挑战. 12小时后,我发现该应 ...

  5. 寻找内存泄漏:一个案例研究

    一周前,我被要求修复一个有内存泄漏问题的webapp. 考虑到过去两年左右的时间里我已经看到并修复了数百个泄漏,我想这有多难. 但是事实证明这是一个挑战. 12小时后,我发现该应用程序中不少于5个漏洞 ...

  6. RT-Thread 内存泄漏分析利器 memtrace+ramdump

    嵌入式开发中,我们经常遇到内存泄漏的问题,却无从下手,使用RT-Thread memtrace 和ramdump功能可以轻松查看内存泄漏 memtrace的使用本文不过多描述,详情请参考 https: ...

  7. Delphi XE 利用FastMM4检测内存泄漏的设置

    1.在项目中使用FastMM4 打开项目文件,让第一个单元引用FastMM4. 2.定义编译条件变量 Shift+Ctrl+F11,打开项目设置窗口,设置Conditional defines. 定义 ...

  8. 一篇文章搞定《Android内存泄漏》

    ------<Android内存泄漏> 什么是内存泄漏 常见的内存泄漏以及规避方式 单例模式引用Activity 非静态内部类 注册的反注册 定时器Timer WebView的内存泄漏 资 ...

  9. Android之内存泄漏以及解决办法(持更)

    Android之内存泄漏以及解决办法 文章链接:http://blog.csdn.net/qq_16628781/article/details/67761590 知识点: 单例造成的内存泄漏原因和解 ...

最新文章

  1. list extend 和 append
  2. 利用Vlan控制与隔离广播风暴
  3. dedephp geteditor(,cms教程:dedecms修改后台编辑器参数GetEditor的方法
  4. 基础知识(9)- Swing用户界面组件
  5. 《C#编程风格》还记得多少
  6. java 动态队列_RabbitMq之动态修改队列参数
  7. 2020年中国OTT大屏服务行业研究报告
  8. 雷军:电视机越大才越舒服!
  9. linux系统shell脚本编程,Linux系统shell脚本编程(一)
  10. 针对业务系统的开发,如何做需求分析和设计1
  11. 大数据标签获取处理步骤_盘点大数据处理引擎
  12. Visual Studio 2010 SP1将支持HTML5和CSS3
  13. matlab循环取出矩阵的某一行并标示上A1 A2 A3
  14. 物料编码,使用有意思的编码还是无意义的编码呢?
  15. 《白帽子讲web安全》第一篇 世界观安全
  16. wifi 小米pro 驱动 黑苹果_小米Pro 15.6英寸(i7 8550U-MX110)游戏本黑苹果
  17. 2022年强网杯rcefile wp
  18. APP支付和H5网页支付有哪些不同?
  19. 《联邦学习实战》杨强 读书笔记十七——联邦学习加速方法
  20. CSS : 七彩呼吸灯

热门文章

  1. 用命令:tar -zxvf,解压tar.gz包失败的问题解决。
  2. Spring Webflux - 01 MVC的困境
  3. 小时候的超级玛丽,开发需要的所有资源
  4. 移动端h5落地页总结(vue cli+vant)
  5. Python求解多机系统暂态分析
  6. 扩展欧几里得算法、ax+by=c求解、ax≡c(mod m)、逆元求解、(b/a)%m计算c++代码
  7. Hibernate+Struts2进行数据的修改
  8. 机器学习实践:基于支持向量机算法对鸢尾花进行分类
  9. WebRTC系列-工具系列之音频混音
  10. QPushButton 设置背景颜色