驯服独角兽:用Chrome DevTools做轻松的javascript内存分析

Taming The Unicorn: Easing JavaScript Memory Profiling In Chrome DevTools

“The Unicorn has a special ability to help it's master when in trouble. When tamed, they will not attack humans or tamed creatures, but will attack anything else with negative karma"

独角兽在遇到麻烦事拥有一种特殊能力去帮助它的主人”被驯服后,他们不会攻击人类或驯服的动物,但会攻击其他不好的事物。



The DevTools Heap Profiler and Timeline Memory view can be used to diagnose memory leaks on both desktop and mobile (via remote debugging). When you first use them however, they can feel like a little like a black box, requiring some trial and error to correctly master.

DevTools堆分析和时间轴内存视图可用于台式机和移动设备(通过远程调试)诊断内存泄漏。当你第一次使用它们,他们可以感觉好像有点像一个黑盒子,需要反复尝试正确地掌握。

In this article, I’ll walk you through how to tame these tools with answers to some common FAQs to help save you time when memory profiling your apps.

在这篇文章中,我将带您通过一些常见的常见问题的解答了解怎样帮你使用工具,帮助您在内存分析您的应用程序时节省时间。

Understanding the Unicorn

了解独角兽

A garbage collector (such as the one in V8) needs to be able to locate objects in your application which are live as well as those which are considered dead (garbage) andcannot be reached. If garbage collection (GC) misses dead objects due to logical errors in your JavaScript, memory consumed by these objects can’t be reclaimed and can end up making your application slow over time.

一个垃圾收集器(如V8中的GC)需要能够找到您的应用程序中的对象,这些对象是活的,但是其实应该是 “死” 的(垃圾) ,因为他们不能达到。如果垃圾收集(GC )由于你的JavaScript逻辑错误而错过回收死对象,这些对象所消耗的内存将不能被回收,最终可以使您的应用程序变慢。

This often happens when you’ve written your code in such a way that variables and event listeners you don’t require for long are still referenced by some code that no longer has a need to keep those references and thus they can’t be correctly cleanedup by GC

这种情况经常发生,当你写你的代码时,一些你很长时间不再需要的变量和事件侦听器他们仍然被一些代码引用,但是这些代码不再被引用,而他们却无法正确的被GC清理。

Remember to check and nullify variables that contain references to DOM elements which may be getting updated/destroyed during the lifecycle of your app. Check object properties which may reference other objects (or other DOM elements). Be sure to keep an eye on variable caches which may accumulate over time. 

记住要检查并且作废那些属于DOM元素并且在其生命周期中可能被更新/销毁的对象。检查可能会引用其他对象(或其他的DOM元素)的对象属性 。一定要留意那些可能会随着时间的推移而积累缓存的变量。

Q: I’ve been told to use the Heap Profiler and Timeline Memory view for detecting memory leaks. What tool should be used first?

问:我已经被告知使用Heap Profiler和Timeline Memory view用于检测内存泄漏。应首先使用什么样的工具?

The Timeline. Use it to diagnose excessive memory usage when you first notice your page has slowed down after extended use. Slowdown was once a classic symptom of a memory leak but it could also be something else – maybe you have a paint or network bottleneck in your page, so make sure to fix the real issue in your page.

时间轴。用它来诊断内存过度使用,长时间使用后当你第一次看到你的页面已经放缓。放缓是一次经典的内存泄漏的症状,但它也可能是别的问题 - 也许你在你的网页上有渲染或网络瓶颈,所以一定要解决在您的网页上真正的问题。

To diagnose whether memory is the issue, go to the Timeline panel and Memory view. Hit the record button and interact with your application, repeating any steps you feel may be causing a leak. Stop the recording. The graph you see will display the memory allocated to your application. If it happens to be consuming an increasing amount of this over time (without ever dropping), it’s an indication you may have a memory leak.

要诊断是否内存是问题,去时间轴面板和内存视图。按下录音键,并与应用程序交互,重复您觉得可能会造成泄漏的所有步骤。停止录音。你看到的图形会显示您的应用程序分配的内存。如果它正好是消耗这个随着时间的推移越来越多(没有下降),这表明你可能有一个内存泄漏。

The profile for a healthy application should look more like a sawtooth curve as memory is allocated then freed when the garbage collector comes in. There’s nothing to worry about here – there’s always going to be a cost of doing business in JavaScript an even an empty requestAnimationFrame will cause this type of sawtooth, you can’t avoid it. Just ensure it’s not sharp as that’s an indication a lot of allocations are being made, which can equate to a lot of garbage on the other side.

一个健康的应用的轮廓应该看起来更像是一个锯齿形曲线,因为开始有内存的分配,然后由于垃圾回收的介入释放。不要担心 - JavaScript做业务处理总是会消耗的,甚至一个空requestAnimationFrame会引起这种类型的锯齿,你无法避免它。只要确保它不是尖锐的,因为这是一个迹象正在分配很多,等同于大量的垃圾在另一侧。

It's the rate of increase in the steepness of this curve that you need to keep an eye on.There is also a DOM node counter, Document counter and Event listener count in the Memory view which can be useful during diagnosis. DOM nodes use native memory and do not directly affect the JavaScript memory graph.

这是增加的速率在陡峭的曲线,你需要留意。内存视图有诊断过程中是有用的DOM节点计数器,文档计数器和事件监听计算在。 DOM节点使用本地内存,并不会直接影响的JavaScript内存图。

Once you suspect you have a memory leak, the Heap profiler can be used to discover the source of the leak.

一旦怀疑你有内存泄漏,Heap profiler可以用来发现泄漏源。

Q: What workflow do you use for diagnosing memory leaks in the Heap Profiler?

问:在Heap Profiler中诊断内存泄漏你用什么样的工作流程?

Diagnosing issues with memory can be tricky, but the best place to start is the Heap profiler's Summary view. Go to Profiles and take a heap snapshot before an intensive part of your code kicks in and then one more after this code has been allowed to run for a while. Repeat. You can then compare the snapshots using the Summary (and other) views to confirm what allocations have been made along with their impact on memory.

诊断内存问题可能会非常棘手,但开始最好的地方是Heap profiler的Summary视图。进入Profiles,并在你代码密集部分载入之前获取heap snapshot,这段代码运行一段时间后再获取一个heap snapshot。重复。然后,您可以使用Summary(和其他)的视图确认已作出什么样的分配连同对内存的影响。

A good workflow for this is the "three snapshot" technique, first used by Loreena Lee and the GMail team to solve some of their memory problems. The steps for this are:

“three snapshot”技术是一个很好的工作流程,第一次用于Loreena 和Gmail团队来解决一些他们的内存问题。这样的步骤是:

  1. Open the DevTools > Profiles  打开DevTools > Profiles
  2. Take a heap snapshot 获取heap snapshot
  3. Perform an action in your app that you think is causing leaks 执行一个你认为在你的应用程序导致泄漏的动作
  4. Take a heap snapshot 获取heap snapshot
  5. Repeat the same stuff once more 再次重复同样的操作
  6. Take a final heap snapshot 获取最终的heap snapshot
  7. Select the most recent snapshot taken 选择最近的snapshot
  8. At the bottom of the window, find the drop-down that says "All objects" and switch this to "Objects allocated between snapshots 1 and 2". (You can also do the same for 2 and 3 if needed)   在窗口的底部,找到下拉“All objects”,切换到“Objects allocated between snapshots 1 and 2”(你也可以切换到“Objects allocated between snapshots 2 and 3”)
  9. In the view you'll see a list of leaked objects that are still hanging around. You can select one to see what is being retained in its retaining tree. 在视图中,你会看到仍然停留的泄漏对象的列表。您可以选择一个,看看在其关系树中有什么被保留

To fix, you'll want to find where in your code you're still retaining these references and properly dispose of them. If there are no leaks the Summary view should be empty.

若要解决此问题,你会想找到你在你的代码中仍保留这些引用的地方,并妥善处置。如果没有泄漏摘要视图应该是空的

 

Note: it sometimes makes sense to do a warm-up action before taking the first heap snapshot as there are cases where you might be doing lazy initialization for global variables on the first invocation. This is mostly a pro-tip for advanced use-cases, but leaving it here in case it is of help.

注意:它有时感觉像第一次快照之前做热身动作,就和你可能会做延迟初始化的全局变量一样。这主要是一个功能给先进的用户,但在这里留下以防它是有用的

Q: I noticed a number of DOM nodes in the heap snapshot where some are highlighted in red and indicated as a "Detached DOM tree" whilst others are yellow. What does this mean?

问:我注意到在一个堆快照里以红色突出显示的很多DOM节点,并表示作为一个“Detached DOM tree”,而其他的是黄色的。这是什么意思?

You'll notice nodes of a few different colors. Red nodes do not have direct references from JavaScript to them, but are alive because they’re part of a detached DOM tree. There may be a node in the tree referenced from JavaScript (maybe as a closure or variable) but is coincidentally preventing the entire DOM tree from being garbage collected.

你会发现几个不同颜色的节点。红色节点不直接从JavaScript引用他们,但还活着,因为他们是一种分离的DOM树的一部分。有可能是从JavaScript引用(也许作为一个闭包或变量)树中的一个节点,但巧合的是防止整个DOM树被垃圾收集。

Yellow nodes however do have direct references from JavaScript. Look for yellow nodes in the same detached DOM tree to locate references from your JavaScript. There should be a chain of properties leading from the DOM window to the element (e.g window.foo.bar[2].baz).

黄节点也有直接从JavaScript引用。看黄色在同一个分离的DOM树节点定位您的JavaScript的引用。从DOM窗口到元素应该有一个链。

Q: What do the Shallow and Retained Size columns represent and what are the differences between them?

问:Shallow和Retained Size表示什么,它们之间的区别是什么?

So, objects can be kept in memory (be alive) in two different ways – either directly by another alive object (window and document are always alive objects) or implicitly by holding references from native part of the renderer (like DOM objects). The latter is what ends up preventing these objects from being disposed by GC automatically, causing leaks. The size of memory held by an object itself is known as the shallow size (generally, arrays and strings have larger shallow sizes).

因此,对象可以保存在内存(活着)两种不同的方式 - 无论是直接由另一个活着的对象(窗口和文档对象总是活着的对象)或隐式引用渲染器的本地部分(如DOM对象)。后者是最终防止这些对象被GC自动处理,导致泄漏。一个目的本身持有的内存的大小被称shallow size(通常,数组和字符串浅的shallow sizes较大)

An object of any size can hold a ton of memory if it prevents other objects from being disposed. The size of memory that can be freed once an object is deleted (and this its dependents made no longer reachable) is called the retained size.

任何大小的一个对象,可容纳一吨的内存,如果它可以防止其他对象被处理。一旦一个对象被删除内存的大小,可以释放,(和其家属不再可达)被称为retained size

Q: There's a lot of data in the constructor and retained views. Where should I start digging into to discover if I have a leak?

问:有很多数据在构造函数及retained视图中。我应该从哪里开始挖掘发现,是否我有一个泄漏?

It's generally a good idea to begin investigation from the first object retained in your tree as retainers are sorted by distance (well, distance to the window).

这通常是一个好主意,开始调查的第一个对象保留在你的树,保留者按距离(距离窗口)进行排序

The object retained with the shortest distance is usually your first candidate for causing a memory leak.

用最短的保留的对象,通常是你的第一个候选者造成内存泄漏

Q: What's the difference between the different Summary, Comparison, Dominators and Containment views?

问: Summary, Comparison, Dominators 和Containment views之间的区别是什么?

You may get some mileage by switching between the different data views available at the bottom of the screen.

你可能会得到一些行驶里程通过屏幕底部的不同的数据视图之间切换。

  • Summary view helps you hunt down objects (and their memory use) based on type grouped by constructor name. This view is particularly helpful for tracking down DOM leaks.

    Summar视图,可以帮助你追捕对象(和内存使用)根据构造器名称类型分组。这视图追查DOM泄漏是特别有用的

  • Comparison view helps you track down memory leaks, by displaying which objects have been correctly cleaned up by the garbage collector. Generally used to record and compare two (or more) memory snapshots of before and after an operation. The idea is that inspecting the delta in freed memory and reference count lets you confirm the presence and cause of a memory leak.

    Comparison视图,可以帮助您跟踪内存泄漏,通过显示哪些对象已正确地清理被垃圾收集器。一般用于记录和比较两个(或更多)的操作之前和之后的内存快照。这个想法是,检查释放的内存的三角洲和引用数,让你确认是否存在,并导致内存泄漏

  • Containment view provides a better view of object structure, helping us analyse objects referenced in the global namespace (i.e. window) to find out what is keeping them around. It lets you analyse closures and dive into your objects at a low level.

    Containment视图提供了更好的视野。帮助我们分析在全局命名空间(即窗口) ,找出对象引用。它可以让你在一个较低的水平,分析闭包和研究你的对象

  • Dominators view helps confirm that no unexpected references to objects are still hanging around (i.e that they are well contained) and that deletion/garbage collection is actually working.

     Dominators视图有助于确认,没有对象的引用仍然徘徊(i.e 包含)并且删除/垃圾收集实际上是工作着的。

Q: What do the various constructor (group) entries in the Heap profiler correspond to?

问:请问Heap profiler的各种constructor(组)条目对应什么?

  • (global property) – intermediate objects between a global object (like 'window') and an object referenced by it. If an object is created using a constructor Person and is held by a global object, the retaining path would look like [global] > (global property) > Person. This contrasts with the norm, where objects directly reference each other. We have intermediate objects for performance reasons. Globals are modified regularly and property access optimisations do a good job for non-global objects aren't applicable for globals.
  • 全局属性) - 一个全局对象(如'window' )和它引用的对象之间的中间对象。如果创建一个对象使用构造函数Person,被一个全局对象引用,固定路径会是什么样子[global] > (global property) > Person.。与此相反,对象直接引用对方。出于性能方面的考虑,我们有中间对象。定期修改全局属性访问优化对非全局对象很好,但并不适用于全局
  • (roots) – The root entries in the retaining tree view are the entities that have references to the selected object. These can also be references created by the engine for its own purposes. The engine has caches which reference objects, but all such references are weak and won't prevent an object from being collected given that there are no truly strong references.
  • roots) - 根条目retaining tree视图中所选对象的引用的实体。这些也可以由引擎为自己的目的创建的引用。引擎有缓存引用对象,但所有这些引用是弱的,并不会防止被收集,有没有真正的强引用对象
  • (closure) – a count of references to a group of objects through function closures
  • (闭包) - 对一组通过闭包函数的对象的引用计数
  • (array, string, number, regexp) – a list of object types with properties which reference an Array, String, Number or regular expression
  • (数组,字符串,数字,正则表达式) - 引用数组,字符串,数字或正则表达式的属性对象类型的列表
  • (compiled code) – simply, everything related to compiled code. Script is similar to a function but corresponds to a <script> body. SharedFunctionInfos (SFI) are objects standing between functions and compiled code. Functions are usually have a context, while SFIs do not.
  •  (compiled code) - 简单地说,一切和编译后的代码相关。脚本类似于一个函数,对应于一个< Script >的身体。 SharedFunctionInfos ( SFI )是在功能和编译代码之间的对象。函数通常是有一个上下文, SFIS没有
  • HTMLDivElement, HTMLAnchorElement, DocumentFragment etc – references to elements or document objects of a particular type referenced by your code.
  • HTMLDivElement , HTMLAnchorElement , DocumentFragment的等等 - 你的代码引用特定类型的元素或文档对象的引用。

Many of the other objects you may see were likely generated during the lifecycle of your code and can include event listeners as well as custom objects, like the controllers below:

你的代码的整个生命周期过程中可能产生许多您可能会看到其他对象可以包括事件侦听器以及自定义对象,如下面的控制器:

Q: Is there anything I should be turning off in Chrome that might be influencing my figures?

问:有没有什么我应该关闭在Chrome中,可能会影响我的数字呢?

When performing any type of profiling using the Chrome DevTools, it is recommended that you either run in incognito mode with all extensions disabled or start Chrome with a custom user data directory (--user-data-dir=”…”).

当使用Chrome DevTools执行任何类型的分析,都建议,你要么运行在隐身模式下的所有扩展禁用或启动Chrome浏览器的自定义用户数据目录

Apps, extensions and even console logging can have an implicit impact on your figures and you want to keep them as reliable as possible.

应用程序,扩展,甚至控制台日志记录可以有一个隐含的影响对您的数据,你想保持他们尽可能可靠


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值