烂俗的问题往往是最容易问到的问题,想必诸多面友都深有体会,因为我们和我们的面试官们都是俗人。但从另一方面来说,烂俗往往有着广阔的延伸空间,一次次让烂俗震惊你,不然于丹老师也就发不了财了。
言归正传,关于堆、栈真的很丰富、很值得研究。了解的不深,暂且按照个人的理解、思路来做笔记。
1---定义。堆、栈都是内存中的数据区,JVM用来存放程序中的数据,当然程序员是不可以直接操作这两个区(都是由JVM操作的,包括new一个对象和垃圾对象回收)。
2---区别。(1):栈中的数据存取速度要比堆中的快许多,据说仅次于CPU中的寄存器(这是不重要的一条)。
(2):栈中的数据是共享的(这点不重要,但是很麻烦,尤其是对理解String的存放重要)。
(3):栈中的数据大小、生存周期必须是固定的(这点也不是很重要)。
(4):栈中存放基础类型变量(byte、short、int、long、float、double、boolean、char),堆中存放引用类型变量(类、数组、枚举、接口)。这条是笼统、概述性质的,不完全正确。
下面具体描述、解释以上4条。
第一条。关于存取速度,不是很重要,了解就可以,没想到什么办法可以测定一下。这个应该是对内存区的分配问题,没能力详细叙述了。
第二条。栈中的数据是共享的。这种问题得举例来说了。例如一段代码
- int a = 1;
- int b =1;
- b = 2;
对于这段代码,JVM的执行如下。首先在栈中开辟空间存放字面值1,然后将a指向1,也可以称a为字面值1的引用。然后,定义变量b的时候,JVM会现在本函数的栈区域中搜索是否有字面值1,如果有,则将b指向1,而不需要再开辟空间存放1字面值。最后,当给b变量重新赋值的时候,JVM同样在栈中搜索2字面值,如果找到,则将b指向这个字面值;如果没找到则重新开辟空间存放2字面值。第三条。栈中的数据大小、生存周期都是已知的。如果在某个函数中声明了基础类型变量,则在函数调用结束的时候变量生存周期结束,即生存周期已知。
第四条。关于什么类型的变量存放在哪时最常问的问题。首先8中基础类型变量毫无疑问的会存放在栈中。其次自己定义的类对象也都会存放在堆中。最后有几种比较特殊的变量需要详细解释。
(1)String类型。首先,如果用String str = new String("asdf");来新建对象,会毫无疑问的存入堆中。但如果使用String str = "asdf",来声明变量则会放入栈中,并遵守栈中数据共享的原则。例如以下代码。
- String a = "abc";
- String b = "abc";
- b = "cde";
首先JVM在本函数的栈中开辟空间新建对象值为“abc”的字符串,并建立引用o指向abc,并在“abc”的内存地址旁记录引用o。当声明定义b字符串的时候,JVM首先在栈中搜索字符串“abc”,如果找到就返回引用o,并将o赋给新的b变量。最后给b字符串重新赋值的时候,也要在栈中搜索,如果没找到则新建对象。(2)数组。因为数组是继承了超类object,所以也要看做对象,即也要存放在堆中。
(3)枚举。同上。
还需要澄清的一点是,当声明、初始化了对象之后,对象的内容的确存放在了堆中,但对象的引用是存放在栈中的
个人网站 www.software8.co