堆内存和栈内存
前言
上网搜了很多关于堆和栈相关的问题,也看了很多的关于堆和栈的博客,看了这么多感觉都是差不多的,整了半天也没大搞懂,然后看到一则评论说:“javacript是范类型。知道咋用就行了,别把简单问题复杂化。有这时间还不如去学学dwr呢。”,我就感觉好像没啥毛病,干嘛去钻那个牛角尖,了解他的基本用法,他的区别,最后会用并且能灵活应用不就够了吗,索性准备将看到的有关文章整理一下。如果有什么不对的话忘大神纠正。
例子
在说这个的时候,我先举个例子吧,正好是做过的一套美团面试题里面的一道题
class A {
String i = "op";
void func(String s) {
s = ""+9;
}
static void test() {
A a = new A();
a.func(a.i);
}
}
问:1. 变量i,s,a在堆还是在栈中?
2. 第8行执行完后a.i的值是什么?
不知道大家看到这道题的时候如果不看答案以及解析的话,多久会做出来呢?(准备找工作的应届生可以好好看看,这只是校招的一面试题)
答案:1. i,s,a都在栈中,new出来的对象A在堆上。
2. 执行完后a.i的值还是字符串op。
解析:
1、这道题考察js堆与栈:栈内存主要用于存储各种基本类型的变量,包括Boolean、Number、String、Undefined、Null以及对象变量的指针,堆主要存储object所以字符串变量i,s以及对象指针a都存在栈中,new出来的对象开辟内存存在堆上,对应地址是指针a存的内容
2、考察参数传递按值传递:a是A类的实例,所以a.i=‘op’,a.func(a.i)这句执行函数,把a.i作为参数传递,该函数会复制一个变量,两个变量完全独立,所以在函数体里只是把复制的那个变量(一个新的局部变量)改变为’op9’,在函数体外的a.i并没有被改变另外补充说明ECMAScript中所有函数的参数都是按值传递的——《高程3》,其实对于参数是对象的情况,实际上也是按值传递,把传参的指针复制出一个完全独立的变量,只是存的内容和传参对象地址一摸一样
感觉大家看完题同时看完解析后就应该了解的差不多了,人家的解析还是比较全面的,下面我就在啰嗦点,分的稍微详细点
什么是堆内存,什么是栈内存
堆内存: 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表;存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了;在JavaScript里面引用类型指的那些就是放在堆内存中
栈内存:存放函数对的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;栈内存首先是一片内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短;JavaScript里面的基本类型都是存在栈内存中。
扩展:基本类型:Undefined、Null、Boolean、Number 和String
区别
1.栈内存存储的是局部变量而堆内存存储的是实体(对象);
2.栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短,同时栈内的数据是可以共享的;
3.栈内存存放的变量生命周期一旦结束就会自动被释放,而堆内存中分配的内存需要程序员手动释放。
总结
通俗点说就是,堆内存存储的是new出来的对象,栈内存存储的是变量的值。
堆和栈 是虚拟出来的概dao念 他们在内存中都du只是一块区域,只是他们的存zhi取规则被人为的限制了,一dao般来说 把类似指针的地址数据放在同一块内存区域这块区域遵守栈的存取规则我们就称之为栈 然后把主要的数据放在同一块内存区域并遵守堆的存取规则 我们称之为堆 其实他们物理上都是一样的东西 只是我们附加上了一些概念 最后之所以这么做 是为了优化存取速度