面试:什么是堆,它和栈有什么区别?
demo1
public class Test01 {public static void main(String[] args) {int i=10;test();}public static void test(){int j=100;}}

以上代码的执行顺序:
- main方法,java虚拟机开辟了一个栈帧,存放变量int i = 10
- 执行到test方法是,java虚拟机栈新开辟一个栈帧,存放变量int j = 100
- test方法执行完后,test栈帧被回收(先进后出),但是main栈帧没执行完就没回收
demo2
说明:下面的图画错了,应该是main技术栈
public class Test02 {public static void main(String[] args) {int [] x=new int[5];x[0]=100;x=null;}}
以上代码的执行顺序:
- 执行main方法,java虚拟机栈开辟了一个栈帧
当执行int [] x = new int[5]时,
栈开辟了x变量空间,该变量存放的是堆的引用地址。
堆开辟了x数组空间,例如0x0001,存放数组的值。数组的元素都设置默认值0
栈里的x存放的是堆的引用地址,例如x = 0x0001。
- 执行x[0] = 100时,
堆会为x[0] = 100
栈的x变量不会变,继续引用堆的地址。
- x = null的时候

当执行x=null时,x引用的内存地址被删除,例如栈帧删除了0x0001。而堆中的数组不再被x使用后,就会变成垃圾,堆不会立即删除,它是采用垃圾回收算法删除。
demo3
public class Test03 {public static void main(String[] args) {int [] x=new int[5];x[0]=100;int [] y=x;x=null;}}
对象和堆的关系
来看demo代码:
public class Test04 {public static void main(String[] args) {Book book1=new Book("java","agan");Book book2=new Book("jvm","agan");}public static class Book{private String name;private String author;public Book(String name, String author) {this.name = name;this.author = author;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}}}

定义了2个对象,栈开辟了2个空间存放堆的地址,堆开辟了2个空间存储数据。
只要每次new一个对象,堆都会为对象分配空间存储。
再来看下面的代码
public static void main(String[] args) {Book book1=new Book("java","agan");Book book2=book1;}

book1就不用再讲解了,定义book2时,把book1的地址复制给了book2,故book1和book2引用了相同的堆地址。
总结:
栈
- 基本数据类型、局部变量存放在栈帧内,方法执行完毕(栈帧出栈)立即释放,节约空间。
- 栈帧内的变量,没有默认值,需要手工设置。
- 栈帧只存留在单个线程中,其他线程访问不了。
- 可以使用-Xss来定义栈内存大小。
- 当堆栈内存已满时,Java运行时抛出java.lang.StackOverFlowError
堆
- 数组和对象存于堆中,用完后(栈帧不再引用),靠垃圾回收算法清除。
- 堆内存对象的变量都有默认值。
- 所有的线程共享堆,即所有栈帧的变量都能引用堆的内存地址。
- 可以使用-Xms和-Xmx的JVM选项来定义堆内存的启动大小和最大大小。
- 如果堆内存已满,则抛出java.lang.OutOfMemoryError:Java堆空间错误。
