1.垃圾回收(Garbage collection)
a.对象创建
初始化赋值: var n = 123; // allocates memory for a number var s = 'abc'; var a = [1, null, 'aaa']; 实例化对象 var d = new Date();
b.javascript垃圾回收,内存出现泄漏一般都发生在回收阶段.
低级语言,需要手动管理内存的分配和释放,javascript作为一种高级语言,垃圾回收器,当对象创建时会自动分配内存,当对象不再被使用的时候会自动释放内存。 如果一个对象不再被引用,就会被GC回收。
http://newhtml.net/v8-garbage-collection/
Mark-and-sweep 算法:
此算法中,会有roots,Garbage-collector 会定期的从这些roots开始查找,查找所有被roots引用的对象或者被这些对象引用的对象(对象被roots引用或者被其它对象引用,就表示还在使用),所有不可到达的对象(没有找到),会被GC回收。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management
内存分代:
脚本中,绝大多数对象的生存期很短,只有某些对象的生存期较长。为利用这一特点,V8将堆进行了分代。对象起初会被分配在新生区(通常很小,只有1-8 MB,具体根据行为来进行启发)。在新生区的内存分配非常容易:我们只需保有一个指向内存区的指针,不断根据新对象的大小对其进行递增即可。当该指针达到了新生区的末尾,就会有一次清理(小周期),清理掉新生区中不活跃的死对象。对于活跃超过2个小周期的对象,则需将其移动至老生区。老生区在标记-清除或标记-紧缩(大周期)的过程中进行回收。大周期进行的并不频繁。一次大周期通常是在移动足够多的对象至老生区后才会发生。至于足够多到底是多少,则根据老生区自身的大小和程序的动向来定。
2.如何使用诊断工具发现性能问题
a.任务管理器

a.timeline

释放过之后

b.Take Heap Snapshot:页面中JavaScript对象和dom节点的内存分配。
Summary

Comparison

Containment
Statistics
c.Record Javascript CPU Profile:记录每个函数的执行时间,Self Time,Total Time

d.Record Allocation Timeline:记录堆上构造函数的内存分配,每个构造函数对应的实例数量,浅层大小,保留大小

e.Record Allocation Profile:记录每个函数的内存使用大小。

举个例子:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;" name="viewport" >
<title>index page</title>
</head>
<body>
<input type="button" value="buttoon" id="btn" />
<script type="text/javascript">
// var btn=document.getElementById("btn");
// btn.addEventListener("click",function(){
var ClassA = function(name){
this.name = name;
this.func = null;
};
var a = new ClassA("a");
var b = new ClassA("b");
b.func = bind(function(){
console.log("I am " + this.name);
}, a);
b.func(); //输出 I am a
//a = null; //释放a
//b = null; //释放self
//模拟上下文绑定
function bind(func, self){
return function(){
return func.apply(self);
};
};
// },false);
</script>
</body>
</html>
由于,a和b都没有释放,可以看到classA下面有两个实例。a 实例的引用关系可以在Retainers 窗口中看到。a是通过self这个形参传入的,返回是个函数,又被func引用,func又是b的属性。

释放a之后的内存:a虽然已经是null,但是a仍然被b引用,所以不会释放。

正确做法:a和b都是null,才会释放。


3.常见的性能问题
a.局部变量意外变成全局变量
b.闭包,用过没有释放
c.setTimeout 没有释放
d.事件绑定之后,不再需要时,没有移除
学习资料:
profile使用:
https://www.2cto.com/kf/201402/281855.html
https://blog.csdn.net/taoerchun/article/details/51480949
原理及总体分析:
http://www.ayqy.net/blog/js%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F%E6%8E%92%E6%9F%A5%E6%96%B9%E6%B3%95/
内存泄漏排查步骤:
1.timeline 查看实时内存,是否不断上升(手动GC)。如果不断上升,说明可能存在内存泄露。
2.记录开始对快照,隔段时间的对快照,compare一下,找出内存泄漏的点。
3.如果明确知道某些操作会导致卡顿或者页面挂掉,可以在操作前后各记录一次对快照,进行对比。找出内存泄漏点。

浙公网安备 33010602011771号