堆(heap)和栈(stack)的区别

JVM 的内存主要分为3个分区

  • 堆区(Heap)只存对象(数组)本身(引用类型的数据),不存基本类型和对象的引用。JVM只有一个堆区,这个“堆”是动态内存分配意义上的堆——用于管理动态生命周期的内存区域。JVM的堆被同一个JVM实例中的所有Java线程共享,它通常由某种自动内存管理机制所管理,这种机制通常叫做“垃圾回收”(garbage collection,GC)。JVM规范并不强制要求JVM实现采用哪种GC算法。
  • 栈区(Stack)– 栈中只保存基础数据类型的对象和对象引用。每个线程一个栈区,每个栈区中的数据都是私有的,其他栈不能访问。栈内有帧(方法调用会生成栈帧)分三个部分:基本类型变量区,执行环境上下文,操作指令区。
  • 方法区 – 又叫静态区,跟堆一样,被所有线程共享。方法区包含所有的class和static变量。方法区包含的都是在整个程序中永远唯一的元素。如:class,satic。

从以下几个方面阐述堆(heap)和栈(stack)的区别:

  1. 申请方式
  • stack:由系统自动分配。例如,声明在函数中一个局部变量 int b; 系统自动在栈中为 b 开辟空间
  • heap:需要程序员自己申请,并指明大小,在 c 中 malloc 函数动态分配内存,对于 Java 需要手动 new Object()的形式开辟空间

在Java中数据类型分为两种:

  • 基本类型(primitive types), 共有 8 种,即 int, short, long, byte, float, double, boolean, char(注意,并没有 string 的基本类型)。这种类型的定义是通过诸如 int a = 3; long b = 255L;的形式来定义的,称为自动变量(自动变量:只在定义它们的时候才创建,在定义它们的函数返回时系统回收变量所占存储空间。对这些变量存储空间的分配和回收是由系统自动完成的。)。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如 int a = 3; 这里的 a 是一个指向 int 类型的引用,指向 3 这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。
  • 包装类数据,如 Integer, String, Double 等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java 用 new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。
  1. 申请后系统的响应
  • stack:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
  • heap:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
  1. 申请大小的限制
  • stack:栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是
    系统预先规定好的,在 Windows下,栈的大小是 2M(也有的说是 1M,总之是一个编译时就确定的常数),如果
    申请的空间超过栈的剩余空间时,将提示 overflow。因此,能从栈获得的空间较小。
  • heap:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,
    自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,
    堆获得的空间比较灵活,也比较大。
  1. 申请效率的比较
  • stack:由系统自动分配,速度较快。但程序员是无法控制的。
  • heap:由 new 分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
  1. heap 和 stack 中的存储内容
  • stack: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,
    然后是函数的各个参数,在大多数的 C 编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量
    是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下
    一条指令,程序由该点继续运行。
  • heap:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。
  1. 数据结构层面的区别
  • 堆是一种经过排序的树形数据结构,每个节点都有一个值,通常我们所说的堆的数据结构是指二叉树。所以堆在数据结构中通常可以被看做是一棵树的数组对象。而且堆需要满足一下两个性质:
    (1)堆中某个节点的值总是不大于或不小于其父节点的值;
    (2)堆总是一棵完全二叉树。

  • 栈是限定仅在表尾进行插入和删除操作的线性表。我们把允许插入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈。栈的特殊之处在于它限制了这个线性表的插入和删除位置,它始终只在栈顶进行。而且栈是一种具有后进先出的数据结构,又称为后进先出的线性表,简称 LIFO(Last In First Out)结构。

  • 堆栈中定义了一些操作。两个最重要的是PUSH和POP。PUSH操作在堆栈的顶部加入一个元素。POP操作相反,在堆栈顶部移去一个元素,并将堆栈的大小减一。
    注意:其实堆栈本身就是栈,只是换了个抽象的名字。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值