内存问题
下图中分了几个块:
- 栈内存(只能从栈顶插入和删除元素,先进后出),存放变量和undifiend(没有内存地址可以指向),它的值都是内存地址。
- 堆内存 存放对象和null,var a = null和var b = null; 指向的是同一个内存地址;
- 池,存放常量,同一个值只占有一块内存,只有三种类型 string number boolean的值
- 函数缓存区, 存放函数,
- 函数加载区,函数执行的时候占有的内存。
分别举例分析:
- a是一个对象,指向的是堆中内存地址
- b(string),c(number),d(boolean)指向的是池中的内存地址。
- 再看m和n,通过构造函数的方式创建数值,会在栈中分别开辟空间存放变量m,和n,而他们都存放的都是池中的内存地址指向123,引用的是同一个值。但是m和n却是不同的。
- 创建函数fun 函数加载区就会存放函数fun,如果我们通过var fun = function(){}的方式创建,这是栈中就会增加一个变量fun,指向函数加载区中的匿名函数。
- 当函数调用的时候,就会在函数缓存区开辟一块空间,普通函数在执行结束,就会被释放。
- new P() 通过new 关键字去调用一个函数, typeof 结果会是object,会在堆内存中开辟一块空间。
堆内存的回收是我们可以控制的,比如说对象a。如果设置为a = null, 堆内存会被回收掉。
常见的内存泄漏问题
内存泄漏:长期的持有一块内存的引用,让它得不到释放。不一定会报错。是一个绑定了执行环境的函数。与普通函数的区别就是他携带了执行环境。
function fun() {
height = 400
}
fun()
console.log(height) //400
function fun1() {
this.mini = '小米'
}
fun1()
console.log(mini) // 小米
内存常驻
节点移除以后,定时器会常驻内存中会 chrome浏览器可以通过下面方法查看cpu占用
闭包引起的内存泄漏
function Boyfriend() {
this.name = '王源'
}
Boyfriend.prototype.findBoyfriend = function() {
var _name = this.name;
return function() {
return _name
}
}
var bf = new Boyfriend()
console.log(bf.findBoyfriend()()) // 王源
console.log(process.memoryUsage())
上面js代码在node中运行
rss总内存 heapTotal 堆内存 heapUsed实际使用的内存 external 引擎底层语言占用的内存
内部的_name变量不会被回收掉。会常驻内存。所以我们应该换成下面的方式去写闭包。
function Boyfriend() {
this.name = '王源'
}
Boyfriend.prototype.findBoyfriend = function() {
var _name = this.name;
return function() {
return _name
}
_name = null
}
var bf = new Boyfriend()
console.log(bf.findBoyfriend()()) // 王源
实际使用的内存变小了。
垃圾回收机制
老的IE浏览器使用的垃圾回收方法。
function fun2() {
var o1 = {
a: 444
}
var o2 = {
a: 444
}
// o1.a = o2;
// o2.a = o1;
}
fun2()
看代码,循环引用不会被回收掉。
function fun1() {
var obj = {};
var obj1 = {};
obj.a = obj1;
obj1.a = obj
}
fun1();
标记-清除算法
v8为什么要限制内存呢?
v8最初为浏览器设计,不要可能出现需要很大内存的场景
v8进行一次1.5GB以上的垃圾回收的时间在50ms到1s之间,为了防止因为垃圾回收造成的js线程暂停时间过长。
v8是一种分代回收的策略,将内存分为新生代,老生代
to空间是需要被回收掉的。
新声带对象的晋升
老生代的标记合并
函数作用域问题
AO是函数作用域
GO是全局作用域
function fun(a, b, c) {
/*
step 1 创建AO对象
AO = {}
step 2 初始化AO对象
AO = {
this: undifined;
arguments: undifined;
a: undifined;
b: undifined;
c: undifined;
inner: undifined;
}
step 3 赋值
AO = {
this: window;
arguments: [length:2,0:1,1:2];
a: 1;
b: 2;
c: undifined;
inner: undifined;
fun: function fun(){}
}
step 4 函数覆盖值
AO = {
this: window;
arguments: [length:2,0:1,1:2];
a: function a() {};
b: 2;
c: undifined;
inner: undifined;
}
*/
console.log(this) // window
console.log(arguments) //
console.log(a)
console.log(b)
console.log(c)
console.log(fun)
console.log(inner)
var inner = 20
function fun() {
}
function a() {
}
}
var global = 20
fun(1,2);
函数调用的时候,会首先创建一个AO对象,创建过程分为上面3步