1.堆栈内存是什么?
1)内存大概分4块,
栈内存存放基本变量和对象的引用,
堆内存存放对象,栈内存中的引用指向堆内存对应的对象,
还有一块是静态变量区,存放静态变量,
最后是程序区,存放系统程序的。
在程序里申请空间的时候申请的都是堆空间,栈是操作系统维护的。
2)堆栈的优缺点
栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享。
堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,但缺点是,由于要在运行时动态分配内存,存取速度较慢。
2.堆栈内存有什么用?
栈内存存放基本变量和对象的引用,
堆内存存放对象,栈内存中的引用指向堆内存对应的对象,
为什么要这样存储
jvm规定栈适合运算,堆适合存东西
3.为什么需要堆栈内存?
来源:http://www.360doc.com/content/18/0826/20/99071_781403615.shtml
回答这个问题之前就要问以前写汇编的为什么写着写着就喜欢把内存分两块来用?
首先汇编里,变量的概念几乎没有了,有的只是各种内存地址,不管是实地址还是虚地址,你访问一个变量就是靠地址,所以如果你不记住一个变量的地址,你就没办法去操作它,这就产生了问题,如果你的程序要1000个变量,你就把他们的地址全记下来吗?
这显然是不现实的,首先这会浪费很多空间,因为几乎任何操作都离不开操作变量,也就是地址,那么就相当于你要用两倍甚至更多的空间来表示你的程序,而一半浪费在地址上,其次这样写程序也是没有效率的,1000个变量,难道你能把他们的地址全背下来吗?或者说当你看到地址0x1234的值赋值给地址0x2345时,你如何记得起0x1234和0x2345是两个干什么用的变量?
所以以一种系统的方法管理内存就显得尤为重要,毕竟我们要用计算机来方便自己,而不是拿来自虐。经过很多人的摸索,人们发现变量主要是两种形式,一种内容短小(比如一个int整数),需要频繁访问,但是生命周期很短,通常只在一个功能内存在,而另一种内容可能很多(比如很长一个字符串),可能不需要太频繁的访问,但生命周期较长,通常很多个功能中可能都要用到,那么自然将这两类变量分开就显得比较理性。
一类存储在栈区,通常是局部变量、操作符栈、函数参数传递和返回值,另一类存储在堆区,通常是较大的结构体(或者OOP中的对象)、需要反复访问的全局变量。
堆区就是各种慢,申请内存慢,访问慢,修改慢,释放慢,整理慢(或者说GC垃圾回收),但优点也不言而喻,访问随机灵活,空间超大,在不超可用内存的情况下你要多大就给多大。
栈区就像临时工,干完就跑,所以超快,但是缺点也很多,比如生命周期短,一般只能在一个功能内存活,又比如你需要事先知道需要多大的栈(事实上绝大多数语言栈区要分配的大小编译期就确定了),而且通常最大栈区可用内存都很小,你不可能往栈区里堆很多数据。
2 js代码执行和堆栈内存的关系
几个概念
1)浏览器在内存中分配一块内存用于执行代码,这块内存叫做执行环境栈ECStack。
2)全局对象GO,浏览器会让window指向GO(浏览器把内置的一些属性方法:isNaN,parseInt,放到一个单独的内存中---堆内存Heap)。
3)任何开辟的内存都有一个16进制的内存地址,方便后期找到这个内存
4)EC执行上下文:代码自己执行所在的环境
- 全局的执行上下文 EC(G)
- 函数中的代码都会在一个单独的私有的执行上下文中处理
- 块级的执行上下文
5)在执行上下文里用于存放创建的变量和值的地方叫做VO变量对象,在函数私有上下文中叫做AO 活动对象(变量对象的一种)
代码要执行,则需要浏览器在内存中分配一块内存用于执行代码,这块内存叫做执行环境栈ECStack。
当执行上下文进入执行环境栈时代码才开始执行(进栈),执行完代码可能会把形成的上下文出栈释放。
ep:比如一个赋值语句
var a = 2;
执行步骤如下
- 1.创建一个值
- 2.创建一个变量
- 3.将二者关联起来
分析:首先值2 是一个基本数据类型存到栈内存中,然后创建一个变量a(放到VO里),将a和2关联在一起。
1)基本数据类型值都是直接存到栈内存中的,
2)引用数据类型值是先开辟一个堆内存,把东西存储进去,最后把地址放在栈中,供变量关联使用
var a = {n:12};
var b = a;
b['n'] = 13;
console.log(a.n)
浏览器开辟一个执行栈供以上代码执行,代码执行的环境进入执行栈后,代码开始执行。
// 1.{n:12}是一个对象,1)创建一个堆内存,2)把键值对存到堆内存中,3)堆内存地址放到栈中,供变量调用
// 2.a指向{n:12}代表的地址AAAFFF000
// 3.b指向地址AAAFFF000
// 4.b基于地址AAAFFF000,找到堆内存,修改堆内存中的属性n的值
// 5.打印a.n 13
var a = {n:12};
var b = a;
b = {n:13};
console.log(a.n)
//b指向新的对象{n:13}对应的地址AAAFFF111
//ab指向不同的对象互不影响
var obj = {
name:'bob',
fun:(function(X){
return x + 10;
})(obj.name)
}
console.log(obj.fn)
//报错undefined.name,因为在创建值的时候就用到了还没有被创建的obj