内存泄漏与溢出

内存泄漏

内存泄漏是指 程序中已经分配了某块内存,但是由于种种原因没有被释放掉,这块内存一直占用着空间。

造成内存泄漏的常见原因有 闭包,未释放的全局变量等。当内存泄漏过多,就会造成可以使用的内存空间越来越小,当到达某一程度,剩余内存空间无法满足程序运行需要时,则会造成内存溢出。

内存溢出

内存溢出是指 剩余内存空间无法满足程序运行需要,而造成的崩溃等现象。

进程与线程

进程

程序的一次运行,它会独自占用一块内存空间,且不同应用的进程之间不会互相影响。

例如 chrome程序 这里开启了多个进程 ,且它的内存空间与其他应用是相互独立的

线程

线程是进程内的一个独立执行单元,用于运行某项任务,是CPU的最小的调度单位。

如果一个进程里面有多个线程,那么这个程序又被称为多线程程序,反之称为单线程程序。

一个进程中至少要有一个运行的线程,主线程,它是进程启动后自动创建的。且应用程序必须允许在某个进程的某个线程上。

一个进程中的数据可以供其中的多个线程直接共享 ,且多个线程之间的数据不能直接共享。

多进程与多线程

多进程指一个程序可以创建多个进程,而多线程指一个进程内有多个线程

多线程的优缺点:

  1. 能够有效提升CPU的利用率
  • 创建多线程会制造更多开销
  • 线程之前切换开销
  • 死锁和状态同步问题

单线程的优缺点:

  1. 顺序编程简单易懂,程序按顺序执行
  • 效率低

对象

对象 (object) 是js中的一种数据类型,准确的来说是引用类型,引用类型相比于基本类型有几个特征:

  1. 引用类型的值是保存在堆内存(Heap)中的
  2. 引用类型的值是按引用访问的
  3. 引用类型的值是可变的
  4. 引用类型的比较是引用的比较

内容:

对象的内容是由一些存储在特定命名位置的值组成的,我们称之为 属性。属性一般并不存在对象容器内部,存储在容器内部的是这些属性的名称,他们就像指针一样,指向这些值真正的存储位置,又被成为引用

访问内容:

访问对象中的属性有两种语法

1
2
3
4
5
var myObj = {
a: 2
};
myobj.a; //2
myobj["a"]; //2

第一种 通过 对象.属性名,通常被称为 属性访问

第二种 通过 对象[“属性名”], 通常被称为 键访问

它们主要的区别在于

  • . 操作符 要求属性名必须满足表示符的命名规范
  • [] 操作符则可以接受任意的UTF-8/Unicode 字符串作为属性名

在对象中,属性名永远都是字符串,如果你使用非字符串类型的值作为属性名,那么它首先会被转成一个字符串,即使是数字也不例外。

1
2
3
4
5
6
7
8
var myObj = {};
myObj[true] = "fish";
myObj[1] = "fishband"
myObj[myObj] = "cool"

myObj["true"]; //"fish"
myObj["1"]; //"fishband"
myObj["myObj"]; //"cool"

可计算属性(es6):

既然说到属性名是字符串类型,那么相应的 属性名也可以进行一些字符串计算

1
2
3
4
5
6
7
8
var handsomePerson = "aMan"
var myObj = {
[handsomePerson + "Name"]: "fish",
[handsomePerson + "Age"]: 18
}

myObj["aManName"]; //fish
myObj["aManAge"]; //18

属性描述符:

在es5之前,js语言本身并没有提供可以直接检测属性特殊的方法,比如判断属性是否只读,但从es5之后,所有的属性都具备了属性的描述符。在使用 Object.defineProperty() 方法定义或修改属性时,可以设置属性的描述符

1
2
3
4
5
6
7
8
9
10
11
var myObj = {}
Object.defineProperty(myObj, "a", {
value: 2,
writable: false, // 是否可以修改属性的值
configurable: true, // 是否可以配置修改 属性描述符
enumerable: false // 是否可以删除
})
myObj.a = 3;
myObj.a; //2
delete myObj.a;
myObj.a //2

不变性:

有时我们会希望属性或对象是不可改变的,在es5中可以通过很多方式实现。重要的一点是:所有的方法创建的都是浅不变性,也就是说,它们只会影响目标对象和它的直接属性。如果目标对象引用了其他对象,其他对象的内容不受影响,仍然是可变的。

  1. 结合 writable: false 和 configurable: false 可以创建一个真正的常量属性(不可修改,重定义或删除)
1
2
3
4
5
6
var myObj = {}
Object.defineProperty(myObj, "MY_LOVE_NUMBER", {
value: 10,
writable: false,
configurable: false
});
  1. 如果你想禁止一个对象添加新属性并保留已有的属性,可以使用 Object.preventExtensions(…)
1
2
3
4
5
6
var myObj = {
a: 2
};
Object.preventExtensions( myObj )
myObj.b = 3;
myObj.b; //undefined
  1. 密封,Object.seal(…) 会创建一个 密封的对象,这个方法实际上会在一个现有对象上调用Object.preventExtensions(…),并把现所有属性标记位 configurable: false,密封之后不能添加新属性也不能重新配置或删除现有属性,但是可以修改

    1
    2
    3
    4
    var myObj = {
    a: 2
    };
    Object.seal( myObj )
  2. 冻结, Object.freeze(..) 会创建一个冻结对象,这个方法实际上会在一个现有对象上调用 Object.seal(…),并把所有 属性标记位 writable: false,冻结之后不能添加新属性也不能重新配置或删除现有属性,也不可以修改

    这个方法是你可以应用在对象上的级别最高的不可变性,它会禁止对于对象本身及其任意直接属性的修改,同时可以使用此方法 对对象进行 深度冻结,首先在对象上调用 Object.freeze(…),然后遍历它引用的所有对象并在这些对象上调用 Object.freeze(…)

    1
    2
    3
    4
    var myObj = {
    a: 2
    };
    Object.freeze( myObj )