Java Spring 堆内存(heap)和栈内存(stack)

Java堆内存(heap)和栈内存(stack)

堆和栈的对比

  • 线程私有的内存区域,由系统自动分配的,一般速度较快
  • 存储基本数据类型的变量和对象的引用,存储函数内部(包括main函数)的局部变量和方法调用和函数参数值
  • 存储方式是后进先出(LIFO)
  • 栈内存的大小在程序启动时就已经确定,存储地址是连续且存在有限栈容量,当栈空间不足时会抛出栈溢出异常(StackOverflowException)

  • 存储对象的公共内存区域(线程共享),堆中的对象可以被所有线程共享
  • 对于面向对象程序来说,new出来的任何对象,无论是对象内部的成员变量,局部变量,类变量,他们指向的对象都存储在堆内存中(但指针本身存在栈中),一般速度较栈慢
  • 储存方式是是一种优先的队列(并不是队列,堆通常是一个可以被看做一棵树的数组对象)
  • 堆的具体储存方式是基于指针的,每个对象都有一个指向其对象头的指针,对象头包含了该对象的元数据,例如对象的类信息、锁的状态、GC信息等等。在 Java 堆的存储空间中,对象实例是可以动态分配和扩展的。每个对象都会在堆上被分配一块连续的内存空间,该空间由一段连续的字节序列组成,包含对象的实例变量和其他信息。
  • 堆内存的大小在程序启动时是不确定的,取决于运行时的需求和系统的内存大小。存储地址通常是链式的,内存较大不会溢出

简单地说,栈用于存储方法(函数)中的局部变量和对象的引用,而堆用于存储对象的实例。

在Spring中,栈和堆的概念同样适用。Spring 允许将对象作为单例(即存储在堆内存上)或非单例(即只存储在栈内存)使用。这取决于对象是否注入到了应用程序的另一个组件中。Spring 容器中的对象实例通常都是单例模式(Singleton)的,也就是说只会创建一个对象实例并共享,因此在多处引用该对象时都使用同一个对象实例,从而减少内存的使用。
在这里插入图片描述

生命周期


栈内存中的数据的生命周期与方法调用的生命周期是一致的,当一个方法被调用时,该方法中的所有局部变量和方法参数都会存储在栈内存中,当方法执行完毕后,内存将会自动释放这些栈内存中的数据。

Java 编译器会自动为每个方法创建一个栈帧(Stack Frame),栈帧包含了方法的所有局部变量、方法参数和返回值等信息。当方法被调用时,栈帧被压入栈顶,当方法执行完毕或者遇到异常时,栈帧被弹出,内存被自动释放。

因此,栈内存中的数据生命周期比较短暂,只在方法执行期间有效,并且内存的分配和释放都由程序自动完成。


堆内存中的数据生命周期与对象的生命周期是一致的。当一个对象被创建时,它会存储在堆内存中,当它不再被引用时,它会被垃圾回收器回收,内存空间会被自动释放。

如何判断一个对象是否不再被引用:

  1. 对象的引用计数器变为0:当一个对象被创建时,Java 虚拟机会自动为该对象分配一块内存空间,并将其引用计数器初始化为 1,在以后的程序执行中,如果有其他对象引用该对象,则引用计数器加 1,如果引用该对象的对象被销毁了,则引用计数器减 1。当对象的引用计数器变为 0 时,表示该对象不再被任何对象引用,可以被垃圾回收器回收。
  2. 对象不再可达:当一个对象不再被任何活动线程所持有,也不再被任何静态引用所引用时,该对象就称为“不可达(unreachable)”对象。不可达对象也可以被垃圾回收器回收。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值