内存、地址、指针、堆、栈、变量

251 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

内存

内存就是暂时存储程序以及数据的地方,相对于外存而言(硬盘是外存的一种),我们在电脑上输入文字,字符的时候,它就会被存入内存中,只有当你选择保存文件的时候,内存中的数据才会被存入硬盘。

内存是CPU能够直接寻址的存储空间,存取速度快,临时存放数据,不能永久保存数据。

image.png

什么是内存地址

计算机把所有信息数字化了,所以它知道自己把一个数据,一条命令记到了内存中的哪些位置,例如下图中,“丁”和“A”的地址都是1000H。

image.png

image.png 一个内存地址=一个内存单元=一个字节(byte)1byte=8bit ;1字节=8位

内存大小:32位/64位操作系统就是和CPU的位数有关,CPU的位数是指CPU一次性可以处理数据或指令的能力。

引用

引用是一个变量的别名,为什么要引入别名?是因为我们想定义一个变量B,由这个变量B来共享变量A的内存空间,所以使用别名是一个好的选择。

变量A是一个内存空间的名字,如果我们给这个内存空间再另外起一个名字(变量B),就是能共享这个内存了,引用(别名)由此而来。

比如:

var obj = {a:1,b:2};
var obj1=obj;

以上我们就可以说变量obj1是变量obj的一个引用。

指针

指针,指向另一个内存空间的变量,我们可以用个指针来索引另一个内存空间中的内容。而指针本身有自己的内存空间。

image.png

堆,栈和队列

三者都属于数据结构。

1.栈(先进后出,后进先出)

image.png

2.基本数据结构的存储(存储栈)

js中,数据类型分为基本数据类型和引用数据类型,基本数据类型有:string、number、boolean、undefined、null、symbol、bigint。在内存中基本数据类型存储在栈中,按值访问。原型类型都存储在栈内存中,是大小固定并且有序的。

image.png

3.执行栈(函数调用栈)

接下来看看js中如何通过栈来管理多个执行上下文。

  • 程序执行进入一个执行环境时,它的执行上下文就会被创建,并被推入执行栈中(入栈)。
  • 程序执行完成时,它的执行上下文就会被销毁,并从栈顶被推出(出栈),控制权交由下一个执行上下文。

js中每一个可执行代码,在解释执行前,都会创建一个可执行上下文。按照可执行代码块可分为三种可执行上下文。

  • 全局可执行上下文:每一个程序都有一个全局可执行代码,并且只有一个。任何不在函数内部的代码都在全局执行上下文。当JavaScript执行全局代码的时候,会编译全局代码并创建全局执行上下文,而且在整个页面的生存周期内,全局执行上下文只有一份。
  • 函数可执行上下文:每当一个函数被调用时,都会为该函数创建一个新的上下文。每个函数都被调用时都会创建它自己的执行上下文。当调用一个函数的时候,函数体内的代码会被编译,并创建函数执行上下文,一般情况下,函数执行结束之后,创建的函数执行上下文会被销毁。
  • Eval可执行上下文:Eval也有自己执行上下文。

因为JS执行中最先进入全局环境,所以处于“栈底的永远是全局环境的执行上下文”。而处于“栈顶的是当前正在执行函数的执行上下文”,当函数调用完成后,这个栈顶的就会被推出(理想情况下,闭包会组织该操作)。

全局环境只有一个,对应的全局执行上下文也只有一个,只有当页面被关闭之后它才会从执行栈中被推出,否则一直处于栈底。

let name = '蜗牛';
function sayName(name) {
    sayNameStart(name);
}
function sayNameStart(name) {
    sayNameEnd(name);
}
function sayNameEnd(name) {
    console.log(name);
}

1.当代码进行时声明:内存堆

name='蜗牛'

sayName = fn;

sayNameStart = fn;

sayNameEnd = fn;

2.执行sayName函数时,会把直接函数压入执行栈,并且会创建执行上下文,执行完毕编译器会自动释放;

4.栈溢出问题

不同浏览器对调用栈的大小有限制,超出限制会出现栈溢出的问题