栈和堆的区别
概念:
栈(stack)是由编译器自动分配和释放的一块内存区域,主要用于存放一些基本类型(如int、float等)的变量、指令代码、常量及对象句柄(也就是对象的引用地址)。
栈内存的操作方式类似于数据结构中的栈(仅在表尾进行插入或删除操作的线性表)。栈的优势在于,它的存取速度比较快,仅此于寄存器,栈中的数据还可以共享。其缺点表现在,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
堆(heap)是一个程序运行动态分配的内存区域,在Java中,构建对象时所需要的内存从堆中分配。这些对象通过new指令“显式”建立,这种分配方式类似于数据结构中的链表。堆内存在使用完毕后,是由垃圾回收(Garbage Collection,GC)器“隐式”回收的。
区别及特点:
1)各司其职
最主要的区别就是栈内存是用来存储局部变量和方法调用。而堆内存是用来存储Java中的对象。引用变量指向的对象都存储在堆内存中。
2)独有还是共享
栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。而堆内存中的对象对所有线程可见,堆内存中的对象可以被所有线程访问,是共享的。
3)异常错误
如果栈内存没有可用的空间用来存储方法调用和局部变量,那么JVM会抛出java.lang.StackOverFlowError。而如果是堆内存没有可用的空间来存储生成的对象,那么JVM会抛出java.lang.OutOfMemoryError。
4)空间大小
栈内存的存储空间要远远小于堆内存。如果你使用递归的话,那么你的栈很快就会被填满。如果递归没有及时跳出,很可能发生StackOverFlowError异常。你可以通过-Xss选项设置栈内存的大小。-Xms选项可以设置堆的开始时的大小和堆的最大值。
5)存储的内容
栈在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。