· ​​StackOverflowError​​​与​​OutOfMemoryError​​​是JVM中常见的有关内存的异常,需结合JVM来;
· 在理解、区分这两个异常前,需要知道JVM中运行时数据区的结构;【见图1的讲解】
· 在了解JVM中运行时数据区的结构后,才能对以上两个异常从内存与线程层面有个好的认识;【见图2的讲解】

一、前置知识:JVM运行时数据区

【JVM】StackOverflowError与OutOfMemoryError_StackOverflow


    见图1,JVM运行时,数据区主要有5大类信息:方法区(JDK 8之后叫做元空间)、JVM栈、本地方法栈、堆、PC寄存器。

· 方法区(元空间)
    在Java虚拟机中,元空间(方法区)是可提供各个线程共享的运行时内存区域,它存储了每一个类的结构信息,例如运行时常量池,字段和方法数据,构造函数和普通函数的字节码内容。它利用的是本地内存,不是JVM内存

· JVM栈
    虚拟机栈也是每条线程私有的区域,里头存储栈帧(Frame),后面会重点介绍栈帧算是重点内容。方法的调用与返回基于栈帧来实现的。

· 本地方法栈
    在Java中调用别的语言代码(例如C/C++)的话就需要用到别的方法栈。JVM会用到传统的栈(C stack)来调用native方法,这个就是本地方法栈的应用,当然这个不是必须实现的,完全取决于虚拟机的实现。

·
    在Java虚拟机中堆是所有线程都可以共享的内存区域,是存放所有类实例和数组对象的地方。在虚拟机启动就根据相关堆参数,创建堆,他也是GC工作的主要区域。
    堆分为年轻代和老年代。

· PC寄存器
    全名叫做 ​​​Program Counter Register​​,概念类比于计算机组成原理中的PC寄存器,存放下一条指令的地址,线程私有,方便线程切换(比如并发),用于保存现场。


二、StackOverflowError与OutOfMemoryError的结构

【JVM】StackOverflowError与OutOfMemoryError_寄存器_02

    见图2,在JVM运行时数据区中:
    · 方法区(JDK 8之后叫做元空间)、堆:是线程共享的,所有线程共用元空间和堆。堆用的是JVM内存,元空间使用本地内存,GC会对这两个部分进行收集。当堆或元空间满溢时,报错:​​OOM(OutOfMemoryError)​​。

    · JVM栈、本地方法栈、、PC寄存器:是线程私有的,每个线程都有属于自己的JVM栈、本地方法栈、PC寄存器。对于栈结构来说,只存在入栈、出栈操作,效率比使用内存结构高,GC不会对栈结构进行收集。(所以我们优化代码时可以利用逃逸分析原理来使得数据存储在JVM栈中。)一旦栈过大,超出范围,就会报错:​​StackOverflowError​​​。
    对于PC寄存器来说,它只存一个地址,不存在溢出,也不会被GC收集。