chrome开发工具系列—— Profiles篇
by addy 原创文章,欢迎转载,但希望全文转载,注明本文地址。
本文地址:https://www.iamaddy.net/2017/06/chrome-dev-tools-profiles/
内存快照工具
profiles的翻译是轮廓的意思,在chrome中可以理解为程序内部剖面的意思。就是可以看到内部到底是怎么运转的。
最新版本的开发工具已经改名为Memory,右侧我们可以看到profiles,这里的意思是内存的一个剖面分析。
右侧我们可以分析三种类型的选择。第一个是堆的快照,最下面的按钮是可以加载之前已经记录的文件。
我们点击Take Snapshot,开始采集堆的快照。采集完成后会生成一个文件,我们可以保存。当然当你想看看你在页面进行了一些操作,导致的快照变化,我们可以采集多个快照。
那么什么是JS的堆栈呢?
JS运行的时候,会有栈内存(stack)和堆内存(heap),当我们用new实例化一个类的时候,这个new出来的对象就保存在heap里面,而这个对象的引用则存储在stack里。程序通过stack里的引用找到这个对象。
例如var a = [1,2,3];,a是存储在stack里的引用,heap里存储着内容为[1,2,3]的Array对象。
上面表格的顶部那些名词可能有点陌生,我们依次来看下:
-
Constructor — 类名
-
Distance — 对象到根的层级距离
-
Objects Count — 当前有多少个该类的对象
-
Shallow Size — 对象所占内存(不包含内部引用的其它对象所占的内存)(单位:字节)
-
Retained Size — 对象所占总内存(包含内部引用的其它对象所占的内存)(单位:字节)
这样可能就会更清楚了吧。那我们展开其中一个看看里面有什么东西。Window这个全局对象下面的东西可以不少,那么像removeClass、trim等等,这就是我们代码中的全局变量。选中每一个变量,可以展开其下面的详细信息,包括引用的次数,占用的大小。
选中单个快照文件,可以看堆的大小的饼图,看看哪些类型占了更多的空间。
内存的快照
如果你不太明白,我建议你亲自写代码体验下,可以参照我讲解的例子。
定义以下函数和变量:
addyxu是一个函数,64051是系统分配了的一个堆的编号,可以理解为指针指向的地址,其下面的原型都会有一个编号。
addyxuInstance 是addyxu类的一个实例,我们可以看到构造函数指向了addyxu,并且编号就是同一个地址。
addyxuArr 是一个数组,而addyxuObject是一个对象,addyxuStr是一个字符串。我们可以看到这三种类型的变量在内存中的表示是不太一样的。elements是数组的元素集合,数组有一个原型proto,原型指向的是Array这个类型,包括了所有数组的一个熟悉方法。同样对象也是,但它还有熟悉名name。
我们来看一个更深一点的例子,下面这段代码一般有点开发经验的读看得懂。但能说的出输出的结果吗?
那么我们可以从堆的快照来分析下
chrome的面板有搜索功能,搜索上面定义的对象。我们发现可以搜到两个定义的类,他们的指向是不一样的。
选中第一个,我们发现有一个实例bbbb。
同样,选中第二个,我们发现有一个实例aaaa。
所以上面连个实例化后的对象实际的指向是不一样了。所以最后的输出结果你知道是什么了吗?
知道为什么会这样吗?为什么MyObj被重写了,原来的原型还保留着。因为原来的原型还有aaaa实例对他的引用呀,所以内存是不会回收第一次定义的那块空间。那么有些代码写的不好,会导致对象回收不及时,造成内存泄露,大家常说的就是dom元素导致泄露。
dom元素与内存
这个图的意思是这样的:
红色的节点表示仍然存在的分离DOM树的一部分,并且DOM树中的某个节点仍然在被JavaScript引用(可能是一个闭包或者某些属性)
黄色的节点表示一个分离DOM树的引用,可能是某个对象的属性或者是一个数组元素,在元素和window之间可能存在着一条属性链(例如 window.a)
那么写什么样的代码会导致上面的两种情况:
红色呢?
与黄色的区别在哪?被删除的元素的子节点test被变量a保持引用。这样导致span无法回收,除非a被销毁。
以上,希望能够帮助大家更好的理解JavaScript的堆栈。
本文为原创文章,可能会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,谢谢合作
本文地址:https://www.iamaddy.net/2017/06/chrome-dev-tools-profiles/
个人知乎,欢迎关注:https://www.zhihu.com/people/iamaddy
欢迎关注公众号【入门游戏开发】
近期评论