栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢
出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻 找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表
中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的
首地址处记录本次分配的大小,这样,代码中的 语句才能正确的释放本内存空间。
另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部
分重新放入空闲链表中。
对比
栈(操作系统):由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
其操作方式类似于数据结构中的栈
栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放
堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由 OS
回收,分配方式倒是类似于链表。
堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成
为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些
堆(数据结构):堆可以被看成是一棵树,如:堆排序
栈(数据结构):一种后进先出的数据结构
Java 中中的数据类型有两种,一种是基本类型(primitivetypes), 共有 8 种,即
int,short, long, byte, float, double, boolean, char(注意,并没有 string 的基本类型)。这种
类型的定义是通过诸如 int a= 3; long b = 255L;的形式来定义的,称为自动变量。值得注意
的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。
如 int a= 3; 这里的 a 是一个指向 int 类型的引用,指向 3 这个字面值。这些字面值的数据,
由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段
值就消失了),出于追求速度的原因,就存在于栈中。
栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:
复制内容到剪贴板代码:
inta=3;
intb=3;
编译器先处理 int a= 3;首先它会在栈中创建一个变量为 a 的引用,然后查找有没有
字面值为 3 的地址,没找到,就开辟一个存放 3 这个字面值的地址,然后将 a 指向 3 的地
址。接着处理 int b= 3;在创建完 b 的引用变量后,由于在栈中已经有 3 这个字面值,便将
b 直接指向 3 的地址。这样,就出现了 a 与 b 同时均指向 3 的情况。
特别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向
一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量
也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字
面值的引用的值也跟着改变的情况。如上例,我们定义完 a 与 b 的值后,再令 a=4;那么,
b 不会等于 4,还是等于 3。在编译器内部,遇到 a=4;时,它就会重新搜索栈中是否有 4
的字面值,如果没有,重新开辟地址存放 4 的值;如果已经有了,则直接将 a 指向这个地
址。因此 a 值的改变不会影响到 b 的值。
另一种是包装类数据,【如 Integer,String, Double 等将相应的基本数据类型包装起来的类。
这些类数据全部存在于【堆】中】,Java 用 new()语句来显示地告诉编译器,在运行时才