栈
栈使用的是一级缓存,通常被调用时临时分配存储空间,调用完毕立即释放。
栈使用的对象: (栈用来开辟变量,存储地址)
1. 函数的返回地址和参数
2. 临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。
堆
- 堆通常可以被看做一棵完全二叉树的数组对象。
- 堆中某个节点的值总是不大于或不小于其父节点的值。
堆使用运行期间分配给代码和栈以外的部分内存。堆分配的内存是所有线程所共享的,他存储的是一个个的对象,在栈中的变量存储的地址指向这些对象。堆使用的是二级缓存,生命周期由jvm虚拟机的垃圾回收算法(GC)来决定,所以存取速度较慢。
堆使用的对象: (堆用于存储对象的实体)
1. 事先不知道程序所需对象的数量和大小。
2. 对象太大,不适合使用栈分配器。
当进程开始时,操作系统创建称为进程堆的默认堆。如果没有使用其他堆,则使用进程堆分配块。当应用程序或 DLL 创建专用堆时,这些堆驻留于进程空间中并且在进程范围内是可访问的。在所有虚拟内存系统中,堆位于操作系统的虚拟内存管理器之上。某些情况下,这些堆在操作系统堆的上层,但语言运行时堆通过分配大的块来执行自己的内存管理。绕开操作系统堆来使用虚拟内存函数可使堆更好地分配和使用块。
典型的堆实现由前端分配器和后端分配器组成。前端分配器维护固定大小块的自由列表。当堆收到分配调用后,它尝试从前端列表中查找自由块。如果此操作失败,则堆将被迫从后端(保留和提交虚拟内存)分配一个大块来满足请求。分配实现时,每个块的分配花费了执行周期,减少了可用存储区。
默认情况下,进程堆执行合并操作。(合并操作是组合相邻的自由块以生成更大的块的操作。)合并操作花费了额外的周期,但减少了堆块的内部碎片。单个全局锁可防止多线程同时使用堆。此锁主要用于保护堆数据结构不受多线程的任意访问。当堆操作过于频繁时,此锁会对性能造成负面影响。
栈和堆的比较
栈和堆都是java用来在RAM(随机存取存储器)中存放数据的地方。
对象的引用存在栈中,对象的实体(分配给对象的变量)存在堆中。
栈
-
优点是:存取速度比堆快。
-
缺点是:存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
堆
-
优点是:可以动态的分配内存大小,生存期也不必事先告诉编译器,java的垃圾收集器会自动收走不再使用的数据。
-
缺点是:由于要在运行时动态的分配内存,存取速度较慢。