You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
var theThing = null;
var replaceThing = function () {
var originalThing = theThing;
var unused = function () {
if (originalThing)
console.log("hi");
};
theThing = {
longStr: new Array(1000000).join('*'),
someMethod: function () {
console.log(someMessage);
}
};
};
setInterval(replaceThing, 1000);
snapshot(v8)
此图是snapshot的json格式图
此图中的索引都是从零开始的
再具体的解释如下:
chrome devtools 里的概念
shallow size:
是指对象自己本身占用的大小, 不包含引用对象内容的大小retained size:
是指不但包含对象自身,还包含该对象所能引用的或者间接引用(parent.child, parent.child.child)
GC roots
GC roots的概念来自与垃圾回收算法,js的垃圾回收�算法是基于根不可达来回收不使用的内存的,就选取某个对象作为初始点,沿着这个对象的引用链往下走,凡是通过这个对象无法访问到(是指通过引用可以获取到对象)的对象就认为是可以被回收的。
如上图5,6,7就无法被访问到,此时就可以认为5,6,7可以被回收了
�
从上面我们可以看出来,所有的对象是以树的形式展示的,devtools中如何显示对象�树的?
对象的保留树
就像我们前面所说的,堆就是由相互连接的对象构成的网络。在数学的世界中,这种结构称作图或者内存图。一个图是由节点和边构成的,而节点又是由边连接起来的,其中节点和边都有相应的标签。
对于不同的属性chrome 会标记不同的标识
对象的属性以及属性值属于不同类型并且有着相应的颜色。每个属性都会有四种类型之一(更详细的上述snapshot里面又讲):
Object count 挡在summary视图模式下查看时,会有这个,按照上述来说对象树的节点是constructor, 属性是边,那么object count 就是�通过这个constructor 构造出来的对象实例数量
巧了还有一个我们可以在devtools里经常看到的就是有些对象是黄颜色标识的有些是�红色标识的,见图, 图中很明显标识�红色和黄色的�原因
在summary视图下第一栏是从constructor而这一栏是分两类的
见上图,他管()的行为叫tag,那就很明显了,在括号()下面的对象�就是全部的这种对象了。
看一次对其中两个对象的识别及分析
代码如下,num2是一个Number对象,不知道为啥,我以字面量分配的num1,我没找到。。。(有待继续)
接下来的图示顺序分析的
常见的内存泄露种类
全局变量
这里bar没有生命就意味着他被global引用了,那么他就不会被回收
被遗忘的计时器或回调函数
此例说明:与节点或数据关联的计时器不再需要,node 对象可以删除,整个回调函数也不需要了。可是,计时器回调函数仍然没被回收(计时器停止才会被回收)。同时,someResource 如果存储了大量的数据,也是无法被回收的。
还有时间监听:
被引用的dom
有时,保存 DOM 节点内部数据结构很有用。假如你想快速更新表格的几行内容,把每一行 DOM 存成字典(JSON 键值对)或者数组很有意义。此时,同样的 DOM 元素存在两个引用:一个在 DOM 树中,另一个在字典中。将来你决定删除这些行时,需要把两个引用都清除。
此外还要考虑 DOM 树内部或子节点的引用问题。假如你的 JavaScript 代码中保存了表格某一个 的引用。将来决定删除整个表格的时候,直觉认为 GC 会回收除了已保存的 以外的其它节点。实际情况并非如此:此 是表格的子节点,子元素与父元素是引用关系。由于代码保留了 的引用,导致整个表格仍待在内存中。保存 DOM 元素引用的时候,要小心谨慎。
闭包
这段代码被引用了无数次了来自meteor
代码片段做了一件事情:每次调用 replaceThing ,theThing 得到一个包含一个大数组和一个新闭包(someMethod)的新对象。同时,变量 unused 是一个引用 originalThing 的闭包(先前的 replaceThing 又调用了 theThing )。思绪混乱了吗?最重要的事情是,闭包的作用域一旦创建,它们有同样的父级作用域,作用域是共享的。someMethod 可以通过 theThing 使用,someMethod 与 unused 分享闭包作用域,尽管 unused 从未使用,它引用的 originalThing 迫使它保留在内存中(防止被回收)。当这段代码反复运行,就会看到内存占用不断上升,垃圾回收器(GC)并无法降低内存占用。本质上,闭包的链表已经创建,每一个闭包作用域携带一个指向大数组的间接的引用,造成严重的内存泄漏。
Meteor 的博文 解释了如何修复此种问题。在 replaceThing 的最后添加 originalThing = null 。
An object size
Shallow size
Retained
为了更好理解retained size 上图
从obj1入手,上图中蓝色节点代表仅仅只有通过obj1才能直接或间接访问的对象。因为可以通过GC Roots访问,所以左图的obj3不是蓝色节点;而在右图却是蓝色,因为它已经被包含在retained集合内。
所以对于左图,obj1的retained size是obj1、obj2、obj4的shallow size总和;右图的retained size是obj1、obj2、obj3、obj4的shallow size总和。
对于obj2,它的retained size是:在左图中,是obj2和obj4的shallow size的和;在右图中,是obj2、obj3和obj4的shallow size的和。
那么V8的GC �root都有哪些呢
还有一些全局变量
built-in object maps: 内建的对象
symbol table: 符号表(没搞明白这是个啥子鬼)
stacks of VM threads;(这个应该是指栈中的 变量)
compilation cache;(编译的缓存)
handle scopes;(v8中的属�术语,v8中每个对象都是被封在handle中的,句柄的scope)
global handles;(全局的句柄)
那么哪些动作会导致�新的分配动作呢
使用�devtools进行profiling的tips
three snapshot method (https://docs.google.com/presentation/d/1wUVmf78gG-ra5aOxvTfYdiLkdGaR9OhXRnOlIcEmu2s/pub?start=false&loop=false&delayms=3000&slide=id.g31ec7af_0_58)
先来一个snapshot1
执行一些能够进行分配的动作再来一个snapshot2
再执行以下相同的操作来一个snapshot3
最后在snapshot3的summary下查看在1和2之间分配的对象
参考
v8类型(知乎上的一篇)
v8类型源码注释
v8-object-representation
js内部编码介绍
v8类型图
snapshot的格式头文件
生成snapshot的cc文件
heap profiling
snapshot格式
easy profiling
常见内存泄露copy于此处
The text was updated successfully, but these errors were encountered: