Java中堆和栈的区别
Java中内存分配策略
静态存储分配
在编译时能确定每个数据在运行时的存储空间,因而在编译时就可以给他们分配固定的内存空间。这种分配策略要求程序不允许有可变数据结构存在,也不允许有嵌套或者递归的结构出现。
栈式存储分配
栈式分配也称为动态存储分配,是由一个类似堆栈的运行栈来实现的。和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能知道。栈式存储分配按照先进后出的原则进行分配。
堆式存储分配
静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例。堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放。
JVM中的堆(heap)和栈(stack)的区别
JVM是基于堆栈的虚拟机,堆和栈都是Java用来在内存中存放数据的地方。
功能和作用
- 栈:可以看成是方法的运行模型,所有方法的调用都是通过栈帧来进行的,JVM会为每个线程都分配一个栈区,JVM对栈只进行两种操作:以帧为单位的压栈和出栈操作。当线程进入一个Java方法函数的时候,就会在当前线程的栈里压入一个栈帧,用于保存当前线程的状态(参数、局部变量、中间计算过程和其他数据),当退出函数方法时,修改栈指针就可以把栈中的内容销毁。
- 堆:唯一的目的就是用于存放对象实例,每个Java应用都唯一对应一个JVM实例,每个JVM实例都唯一对应一个堆,并由堆内存被应用所有线程共享。
- 总结:通俗来讲堆主要用来存放对象,栈主要用来执行程序。
性能和存储要求
- 栈的性能比堆要快,仅次于位于CPU中的寄存器。但是在分配内存的时候,存放在栈中的数据大小与生存周期必须在编译时是确定的,缺乏灵活性。
- 堆可以动态分配内存大小,编译器不必知道要从堆里分配多少存储空间,生存周期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据,因此可以得到更大的灵活性。但是,由于要在运行时动态分配内存和销毁对象时都需要占用时间,所以效率低。由于面向对象的多态性,堆内存分配时必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定。
内存的分配与回收
- 函数中基本类型和对象的引用都是在栈内存中分配。当在一段代码块中定义一个变量时,由于这些变量大小可知,生存周期可知,处于追求速度的原因,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间。
- 对于引用类型,Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配。也就是说在建立一个对象时,从两个地方都分配内存,在堆中分配的内存实际用于建立这个对象,而在栈中分配的内存只是一个指向这个堆对象的引用而已。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。