oom:OOM,全称“Out Of Memory”,翻译成中文就是“内存用完了”,来源于java.lang.OutOfMemoryError。看下关于的官方说明: Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector. 意思就是说,当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error(注:非exception,因为这个问题已经严重到不足以被应用处理)。

🌳 虚拟机栈也称为Java栈,每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧(Stack Frame)。

  1. Java虚拟机栈是线程私有的,它的生命周期与线程相同(随线程而生,随线程而灭)。
  2. 栈帧包括局部变量表、操作数栈、动态链接、方法返回地址和一些附加信息。
    1. 局部变量包括: (8种基本类型,对象的引用地址)
  3. 每一个方法被调用直至执行完毕的过程,就对应这一个栈帧在虚拟机栈中从入栈到出栈的过程。

image.png
栈的优点:
栈是一种快速有效的分配存储方式,访问速度仅仅次于程序计数器
JVM直接对Java栈的操作只有两个
每个方法执行,伴随着进栈(入栈、压栈)
执行结束后的出栈工作
对于栈来说不存在垃圾回收问题(为什么)
虚拟机栈里的栈帧即对应代码中的一个方法。代码运行的过程,即栈帧入栈出栈的过程。
一个方法执行完,栈帧出栈后,即被销毁。只有入栈出栈这样简单的操作,不需要设计复杂的垃圾回收 算法来回收。随着方法的执行,线程的结束正常回收即可。
在递归函数中,该方法还没有结束,就一直不会出栈,如果循环的次数过多,栈空间有被挤爆的可能。会出现StackOverflowError 栈溢出。栈溢出也是内存溢出的一种情况。可通过-Xss (stack size)设置栈大小。

虚拟机栈大小的调整

Java虚拟机规范允许虚拟机栈的大小固定不变或者动态扩展。

  • 固定情况下:如果线程请求分配的栈容量超过Java虚拟机允许的最大容量,则抛出StackOverflowError异常;
  • 可动态扩展情况下:尝试扩展的时候无法申请到足够的内存;或者在创建新的线程的时候没有足够的内存去创建对应的虚拟机栈,则会抛出OutOfMemoryError异常。

可以通过 java -Xss<size> 设置 Java 线程堆栈大小,或者在idea中 help -> edit vm option中改变大小

栈的存储单位
每个线程都有自己的栈,栈中的数据是以栈帧(Stack Frame)的格式存在
在这个线程上正在执行的每个方法都各自对应一个栈帧
栈帧是一个内存区块,是一个数据集,维系着方法执行过程中的各种数据信息

方法返回地址:
方法的结束方式有两种:
一种正常结束,以return 为代表,这种退出方式称为:正常完成出口(Normal Method Invocation Completion)
一种异常退出,这种退出方式称为异常完成出口(Abrupt Method Invocation Completion)
无论采用何种方式退出,在方法退出之前,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。
一般来说,方法正常退出时,调用者PC计数器的值就可以作为返回地址,栈帧中很可能会保存这个计数器值。而方法异常退出时,返回地址是要通过异常处理器来确定的,栈帧中一般不会保存这部分信息。 方法退出的过程实际上等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有的话)压入调用都栈帧的操作数栈中,调用PC计数器的值以指向方法调用指令后面的一条指令等。

栈运行原理:
不同线程中所包含的栈帧是不允许存在相互引用的,即不可能在一个栈帧中引用另外一个线程的栈帧

如果当前方法调用了其他方法,方法返回之际,当前栈帧会传回次方法的执行结果给前一个栈帧,接着,虚拟机会丢弃当前栈帧,使得前一个栈帧重新成为当前栈帧。
Java方法有两种返回函数的方式,不管哪种返回,都会导致栈帧被弹出。