介绍一下Java运行时数据区各个区域功能
- Java运行时数据区主要包含6个部分分别是:堆、方法区、虚拟机栈、程序计数器、本地方法栈、运行时常量池。
- 堆:java堆被所有线程所共享,其唯一的用途就是存放对象实例,几乎所有的对象实例都在堆中分配内存。
- 方法区:也是被各个线程所共享的区域,它用于存储已被虚拟机加载的类信息、常量、静态变量
- 运行时常量池:JDK1.7 及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。这块区域在 1.7 之前原来是方法区的一部分,运行时常量池存储的东西较为复杂,主要分为字面量和符号引用。字面量存放的字面量主要包括 常量(final 修饰的),比如:final int x = 1、静态变量(static 修饰的),还有一些其他的字面量。
符号引用:符号引用主要包括:类的完全限定名、字段名称和描述符、方法名称和描述符,包括很多符号,比如:() 也可以看做符号引用。 - 虚拟机栈也是线程私有的,所以它的生命周期与程序计数器相同。虚拟机栈描述的是 Java 方法执行的内存模型。
- 程序计数器是一块很小的区域,它存储的是当前线程正在执行的字节码的地址,程序计数器是唯一的一块在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 的区域。由于它是线程私有的,所以它的生命周期随着线程的创建而创建,随着线程的结束而死亡 。
- 本地方法栈与虚拟机栈类似,虚拟机栈是执行 Java 方法开辟的内存空间,而本地方法栈是执行 Native 方法开辟的内存空间。
什么情况下会发生栈内存溢出?
思路: 描述栈定义,再描述为什么会溢出,再说明一下相关配置参数,OK的话可以给面试官手写是一个栈溢出的demo。
我的答案:
- 栈是线程私有的,他的生命周期与线程相同,每个方法在执行的时候都会创建一个栈帧,用来存储局部变量表,操作数栈,动态链接,方法出口等信息。局部变量表又包含基本数据类型,对象引用类型
- 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常**,方法递归调用本身就会产生这种结果。**
- 如果Java虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是无法申请到足够的内存去完成扩展,或者在新建立线程的时候没有足够的内存去创建对应的虚拟机栈,那么Java虚拟机将抛出一个OutOfMemory 异常。(线程启动过多)
- 参数 -X