调用堆栈(2)--内存空间详解

什么是内存

从硬件层面看,计算机内存是由大量的 flip flops 所组成的(这里大概查了下,即大量的二进制电路所组成的,每个 flip flop 是一个电路拥有两种稳定状态,可用于保存状态信息)。每个 flip flop 包含少量晶体管并能够存储一个比特位。单个的 flip flops 可以通过一个唯一标识符寻址,所以就可以读和覆写它们。因此,理论上,我们可以把整个计算机内存看成是由一个巨大的比特位数组所组成的,这样就可以进行读和写。

内存中存储着很多东西:

  • 全部程序使用的全部变量及其它数据。
  • 程序代码,包括操作系统的代码。

内存空间的管理

js内存生命周期包括

  • 分配所需内存
  • 使用分配到的内存(读,写)
  • 释放,归还内存(垃圾回收)

内存分配

  • 静态分配(栈)
  • 动态分配(堆)

编译器和操作系统一起协作来为你进行内存管理,当编译代码的时候,编译器会检查基本数据类型并提前计算出程序运行所需要的内存大小。在所谓的栈空间中,所需的内存大小会被分配给程序。这些变量所分配到的空间之所以被称为栈空间是因为当调用函数的时候,函数所需的内存会被添加到现存内存的顶部。当函数中断,它们被以 LIFO(后进先出) 的顺序移除。

有时我们不能在编译阶段判断所需内存大小,比如接受用户输入的数据.因此,就不能够在栈中为变量分配内存空间。相反,程序需要在运行时显式地从操作系统分配到正确的内存空间。这里的内存是由内存堆空间所分配的。

两者区别:


内存空间和调用栈的关系

以v8引擎为例,V8引擎在chrome和node中负责解析和执行js,其简化来说包括两部分:Heap(用于分配内存),call stack(执行栈);
也就是说内存空间和执行栈是并列的


内存空间都包含什么

  • 栈: 存放变量
  • 堆: 存放复杂对象
  • 池: 一般也归为栈,存放常量(常量池)

数据怎么在内存空间中储存

  • 基础数据类型: 存放在栈内存中(不包括闭包)
    • 此类型数据占有固定大小内存空间,按值直接访问
    • null,undefined,Boolean,string,number,symbol
  • 引用类型/(闭包): 存放在堆内存
    • 此类型数据所占空间不定,会随数据变化
    • 但内存地址大小固定,因此内存地址储存在栈空间中
    • 访问此类型是通过内存地址来找到具体值,称为引用访问
    • object(array function Set(es6) Map(es6))


在计算机的数据结构中,栈比堆的运算速度快

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var a = 20;
var b = a;
b = 30;
// 这时a的值是多少? 20

// ---------------
var a = { name: '前端开发' }
var b = a;
b.name = '进阶';
// 这时a.name的值是多少 '进阶'

// ---------------
var a = { name: '前端开发' }
var b = a;
a = null; // 改变了a的引用地址
// 这时b的值是多少 { name: '前端开发' }

// ---------------
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
a.x // 这时 a.x 的值是多少 undefined
b.x // 这时 b.x 的值是多少 {n: 2}
/*
解:
.优先级高于=;a.x是undefined,即a=b={n:1,x:undefined}
从右向左运算,a={n:2}后,即改变了原来a的引用,和b已经没关联了
a.x=a即a.x={n:2},此时的a.x是引用数据{n:1,x:undefined}中的x,
数据变为{n:1,x:{n:2}},此时b能访问到,a已经访问不到
*/

内存回收,泄漏见下篇内存机制