本文是V8引擎详解系列的第六篇,重点内容是关于V8的内存结构,以及一般状况下内存的使用过程,本文会先从基本概念入手,了解V8的堆栈结构,最后描述一个对象建立后在内存中的生命周期(本文不会有太多GC相关内容,关于垃圾回收会在下一篇详细描述)文末会有已经完成的系列文章的连接,本系列文章还在不断更新欢迎持续关注。javascript
一般咱们说的计算机由5个部分组成,控制器、运算器、输出设备、输出设备、存储器,而咱们说的内存一般属于存储器,而程序运行时CPU须要调用的指令和数据只能经过内存获取(硬盘只有存储功能,执行时会将数据缓存到内存中),因此不论是什么语言的程序,运行时都依赖内存,而内存生命周期基本都是一致的:java
而不少文章讲 javascript的内存如何如何,事实上,我认为这种说法是不许确的,自己javascript只是一种语言,真正进行内存调用分配的是javascript依赖的引擎,本文就来简单聊一下V8的内存结构。面试
在V8引擎中,能够先粗犷的分为两个部分 栈 和 堆。
那栈指的就是 调用栈,首先栈的特色后进先出(普通意义上栈的特色在这里不会细说,网上相关文章不少),同时栈空间是连续的,在须要分配空间和销毁空间操做时,只须要移动下指针,因此很是适合管理函数调用。缓存
而正由于栈空间是连续的,那它的空间就注定是很是有限的,因此不方便存放大的数据,这时咱们就使用了 内存堆 来管理保存一些大数据。bash
这里要先说一下两种变量类型:基本类型变量 和 引用变量类型,基础变量类型包括undefined, null, Number, String, Boolean, Symbol,而引用变量类型包括:Object、Array、Function等等,而实际上在js中Array、Function这些都是基于Objct的,咱们能够理解引用变量类型指的就是Objct。
(这里可能有人会说 null不该该是空指针对象类型吗,typeof null === 'Object'应该算是对象,事实上这里是一个设计上的历史遗留问题,而对V8系统来讲不管是null和Undefined都只是一个存在与栈里的固定的值)。ide
由于基础变量类型的值一般是简单的数据段,占用固定大小的空间,因此会存储在 栈 中,而对象大小不定且一般会占用较大空间因此会存储在 堆 中,而在栈空间会保存对象存储在堆空间的地址。函数
咱们将一段代码经过一张图来简单看一下。post
var a = 123;
var b = 'abc';
var c = {x: 1};
var d = 123;
var f = c;
var g = {x: 1};
复制代码
基础类型的值在建立时会开辟一块内存空间,将内存地址存储在对应的变量上,若是此时再建立一个基础类型等同于以前建立过的值,会直接将地址存储在新建立的变量上,因此就会有 a === d 。学习
那么若是建立一个对象,就会在堆中开辟一块空间用来存储对象,将内存地址存储在对应的变量上,若是此时建立一个新的变量(f)赋值为以前所建立的存储对象地址的变量(c),那么会将c存储的堆内存地址赋值给f,就会有 c === f。大数据
若是此时再建立一个新的对象变量g,就会在堆中再开辟一块空间来建立对象,将地址赋予g,可是即便对象内容同样,地址不一样指向的也是两块空间,就会有 g !== c。
关于函数调用也很好理解,也是用一段代码一张图来表示以下:
function main() {
func1();
}
function func1() {
func2();
func3();
};
function func2() {};
function func3() {};
main();
复制代码
栈的管理一般比较容易一点,经过上下移动指针来管理便可,而堆的管理相对复杂不少,而咱们一般说的垃圾回收等也主要针对堆来讲的。
咱们先来看一下内存的结构组成:
新生代内存区(new space)
新生代内存区会被划分为两个semispace,每一个semispace大小默认为16MB也就是说新生代内存区一般只有32MB大小(64位),而这两个semispace分别是from space 和 to space(具体有什么用下文会说),一般新建立的对象会先放入这两个semispace中的一个。
老生代内存区(old space)
一般会较为持久的保存对象,也分为两个区域 old pointer space 和 old data space分别用来存放GC后还存活的指针信息和数据信息。
大对象区(large object space)
这里存放体积超越其余区大小的对象,主要为了不大对象的拷贝,使用该空间专门存储大对象。
单元区、属性单元区、Map区(Cell space、property cell space、map space)
Map空间存放对象的Map信息也就是隐藏类(Hiden Class)最大限制为8MB;每一个Map对象固定大小,为了快速定位,因此将该空间单独出来。
代码区 (code Space)
主要存放代码对象,最大限制为512MB,也是惟一拥有执行权限的内存
堆内存空间分红了有不一样功能做用的空间区域,大对象区,map区,代码区没什么好说的,重点仍是了解一下新生代内存区和老生代内存区。
这里咱们假设建立了一个对象 obj,先说一下新生代内存区的两个space也就是 from space 和 to space 的做用。
也就是说建立的对象会在to space 和 from space 之间转移,也就是所谓的 to --> from, from --> to 的角色互换过程。
(本文重点不是垃圾回收,因此不少GC相关的内容不会很详细)
接下来讲一下老生代内存区,如今继续看上文说的那个对象 obj:
本文主要学习了一些内存的概念以及V8的内存结构,以及各部分的一些做用,事实上不管是面试仍是平常工做中,理解V8的内存机制会对咱们带来很大帮助,那在下一篇我会重点说一下V8的内存回收机制。若是有什么错误,请在评论中和做者一块儿讨论,若是您以为本文对您有帮助请帮忙点个赞,感激涕零。
V8引擎详解(一)——概述
V8引擎详解(二)——AST
V8引擎详解(三)——从字节码看V8的演变
V8引擎详解(四)——字节码是如何执行的
V8引擎详解(五)——内联缓存
V8引擎详解(六)——内存结构