我们都知道堆和栈,但是不知道为什么有这些。本文从原理讲述一下
目录
简单点说,Java 划分了堆和栈是为了更好的使用内存,提高内存使用效率。
一、什么是堆,什么是栈
Java的堆(Heap)和栈(Stack)都是内存中的两种不同的存储区域,用于存储程序执行过程中的数据。
1.1 堆
堆则是一种基于树的数据结构,由于对象和数组的大小不固定,因此不能将它们存储在栈内存中,否则会导致栈内存不够用,因此堆是存储对象及其实例变量的地方。堆的大小不固定,由虚拟机自动管理,当堆空间不足时,就会抛出OutOfMemoryError异常。堆内存的特点是动态分配和释放,因此对象和数组的大小可以动态调整,堆内存的使用效率也比较高。同时,由于堆内存是不连续的,因此访问速度相对较慢。
堆是一种树型数据结构,主要是因为它需要支持高效的动态内存分配和回收。在堆中,内存空间是按照树形结构组织的,其中每个节点都代表一个内存块,包括该内存块的大小和状态(已分配或未分配)。
堆的树形结构使得它可以支持高效的内存分配和回收操作。当需要分配一块内存时,堆会从根节点开始遍历树,寻找一块足够大的未分配内存块,将其分配给程序。同样地,当需要释放某块内存时,堆会从该内存块的位置开始,递归地合并相邻的未分配内存块,形成一个更大的未分配内存块,最终恢复该内存块到未分配状态,以便后续程序继续使用。
由于堆是一种动态数据结构,内存的分配和回收是频繁进行的操作。而树形结构具有较好的扩展性和灵活性,因此堆被设计成树型结构,以支持高效的内存分配和回收。
1.2 栈
栈是一种先进后出的数据结构,存储的是基本类型和对象的引用(即指向对象在堆中存储位置的指针),每个线程都拥有自己的栈空间,栈的大小固定且较小,由虚拟机自动管理,当栈空间不足时,就会抛出StackOverflowError异常。当一个方法被调用时,它会在栈内存中创建一个栈帧,该栈帧存储了方法的参数、局部变量和方法返回值等信息。当方法执行完成后,该栈帧将被弹出并从栈内存中移除。由于栈内存的数据存储方式是连续的,因此访问速度比较快,同时由于栈帧的动态创建和销毁,栈内存的管理比较容易。
栈是一种线性数据结构,只能在栈顶进行插入和删除操作。因为在栈中,元素的插入和删除都只会发生在栈顶,因此使用数组结构可以方便地实现这种操作。数组可以直接访问任意位置上的元素,因此在栈顶插入和删除元素时,只需要在数组的末尾进行插入和删除即可,这样可以保证操作的时间复杂度为O(1)。同时,使用数组结构还可以避免因为需要频繁地进行内存分配和释放导致的时间和空间开销,提高了栈的效率。因此,栈通常是使用数组结构来实现的。
1.3 总结
所有的线程共享同一个堆空间,其中的对象可以被所有线程访问,而栈空间则是独立的,每个线程拥有自己的栈空间。
- 当Java程序首先被javac