JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存

28365365体育在线备用 🌸 2026-01-18 22:27:40 🎨 admin 👁️ 7439 ❤️ 743
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存

目录

一、JVM基本介绍——概念、组成、重点

1.1 JVM是什么

1.2 JVM由哪些部分组成,运行流程是什么?

1.3 JDK、JRE、JVM 关系

1.4 学习什么

二、JVM组成

2.1 什么是程序计数器

2.2 你能详细地介绍堆吗

2.3 什么是虚拟机栈

2.4 垃圾回收是否涉及栈内存

2.5 栈内存分配越大越好吗

2.6 方法内的局部变量是否线程安全

2.7 什么情况下会导致栈内存溢出

2.8 堆栈的区别是什么

2.9 介绍下方法区

2.10 直接内存

2.11 总结

javap -v xx.class #打印堆栈大小,局部变量的数量和方法的参数

一、JVM基本介绍——概念、组成、重点

1.1 JVM是什么

JVM(Java Virtual Machine,即java虚拟机),java程序的运行环境(java二进制字节码的运行环境)。

JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。针对java用户,也就是拥有可运行的.class文件包(jar或者war)的用户。里面主要包含了jvm和java运行时基本类库(rt.jar)。rt.jar可以简单粗暴地理解为:它就是java源码编译成的jar包。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java能够“一次编译,到处运行”的原因。

JVM是Java跨平台的关键,因为它屏蔽了不同操作系统之间的差异,可以让相同的Java程序在不同的操作系统上运行出相同的结果。

好处:

一次编写,到处运行

自动内存管理,垃圾回收机制

1.2 JVM由哪些部分组成,运行流程是什么?

JVM由哪些部分组成:类加载子系统,运行数据区(方法区、堆、程序计数器、虚拟机栈、本地方法栈),执行引擎(解释器、即使编辑器、垃圾回收)、本地库接口

JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载器)、Execution engine(执行引擎);两个组件为Runtime data area(运行时数据区)、Native Interface(本地库接口)

Class loader(类加载器):根据给定的全限定名类名(如:java.lang.Object)来装载class文件到运行时数据区中的方法区;

Execution engine(执行引擎):执行引擎也叫解释器,负责解释命令,交由操作系统执行;

Native Interface(本地接口):与native libraries交互,是其它编程语言交互的接口。

Runtime data area(运行时数据区域):这就是我们常说的JVM的内存,我们所有写的程序都被加载到这里,之后才开始运行。由五部分组成,Method Area/MateSpace 方法区/元空间、Heap 堆、PC Register 程序计数器、JVM Stacks 虚拟机栈、Nativa Method Stacks 本地方法栈

运行流程、作用 :首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区内;而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。

GC垃圾回收主要针对 运行数据区中的堆空间。

1.3 JDK、JRE、JVM 关系

我们在 JVM常见面试题(一):JVM是什么、由哪些部分组成、运行流程是什么,JDK、JRE、JVM的联系与区别 中已详细介绍过JDK、JRE、JVM的联系与区别,此处简单讲解下:

JDK(Java Development Kit,Java开发工具包)、JRE(Java Runtime Environment,Java运行时环境)、JVM(Java Virtual Machine,即java虚拟机)。

JDK是 Java 语言的软件开发工具包(SDK)。在JDK的安装目录下有一个jre目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib合起来就称为jre。

JDK包含了JRE,JRE包含了JVM。

如果只想运行Java程序,只需安装JRE即可(少数情况例外);如果想要开发Java程序,则需要安装JDK。

JDK是用于java程序的开发,而jre则是只能运行class而没有编译的功能;Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。

1.4 学习什么

二、JVM组成

2.1 什么是程序计数器

程序计数器:线程私有的,内部保存的字节码的行号。用于记录正在执行的字节码指令的地址。

javap -v xx.class #打印堆栈大小,局部变量的数量和方法的参数

2.2 你能详细地介绍堆吗

线程共享的区域:主要用来保存对象实例,数组等,当堆中没有内存空间可分配给实例,也无法再扩展时,则抛出OutOfMemoryError异常。

Java堆主要组成部分:

元空间保存的类信息、静态变量、常量、编译后的代码(Jdk1.8引入)

年轻代被划分为三部分,Eden区和两个大小严格相同的Survivor区,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到老年代区间。

老年代主要保存生命周期长的对象,一般是一些老的对象

总结:你能详细地介绍Java堆吗?

线程共享的区域:主要用来保存对象实例,数组等,内存不够则抛出OutOfMemoryError异常

组成:年轻代+老年代

年轻代被划分为三部分,Eden区和两个大小严格相同的Survivor区

老年代主要保存生命周期长的对象,一般是一些老的对象

Jdk1.7和1.8的区别

1.7中有有一个永久代,存储的是类信息、静态变量、常量、编译后的代码

1.8移除了永久代,把数据存储到了本地内存的元空间中,防止内存溢出

2.3 什么是虚拟机栈

Java Virtual machine Stacks (java 虚拟机栈),早期也叫Java栈。每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个栈帧(stack Frame) ,对应着一次次的Java方法调用。一次方法的调用,就是栈帧入栈到出栈的过程;

虚拟机栈是线程私有的,生命周期和线程一致,其作用为 主管Java程序的运行,它保存方法的局部变量(8大基本数据类型、对象的引用地址)、部分结果,并参与方法的调用和返回

每个线程都有自己的栈,栈中的数据都是以栈帧(stack Frame)的格式存在。栈帧是一个内存区块,是一个数据集,维系着方法执行过程中的各种数据信息,存储:局部变量表(Local variables)、操作数栈(operand stack) (或表达式栈)、动态链接(Dynamic Linking) (或指向运行时常量池的方法引用)、方法返回地址(Return Address) (或方法正常退出或者异常退出的定义)、一些附加信息

每个线程运行时所需要的内存,称为虚拟机栈,先进后出

每个栈由多个栈帧(frame)组成,对应着每次方法调用时所占用的内存。栈帧对应的方法执行完后,栈会将该方法对应的栈帧弹出栈,释放内存

每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

多线程下

public class StackTest {

public static void main(String[] args) {

StackTest stackTest = new StackTest();

stackTest.methodA();

}

public void methodA() {

int i = 10;

int j = 20;

methodB();

}

private void methodB() {

int k = 30;

int m = 40;

}

}

补充:本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的。其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。

2.4 垃圾回收是否涉及栈内存

垃圾回收主要指就是堆内存,不涉及栈内存,当栈帧弹栈以后,内存就会释放。

1)什么是垃圾回收?

垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存泄露。有效地使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。

2)结合2.5,因为栈帧对应的方法执行完后,栈会将该方法对应的栈帧弹出栈,释放内存,因此垃圾回收不涉及栈内存。

2.5 栈内存分配越大越好吗

未必,默认的栈内存通常为1024k

栈帧过大会导致线程数变少,例如,机器总内存为512m,目前能活动的线程数则为512个(512m/1024k=512);如果把栈内存改为2048k,那么能活动的栈帧就会减半(512m/2048k=256)

(栈内存的大小不会影响方法执行的速度,而且由于计算机硬件的储存大小是有限的,栈空间内存设置过大,创建线程数量较多时会出现栈内存溢出OutofMemoryError,导致最大线程数减少,得不偿失。同时,栈内存也决定方法调用的深度,栈内存过小则会导致方法调用的深度较小,如递归调用的次数较少)

2.6 方法内的局部变量是否线程安全

如果方法内局部变量没有逃离方法的作用范围,它是线程安全的

如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全

2.7 什么情况下会导致栈内存溢出

栈帧过多导致栈内存溢出。典型问题:递归调用,没有结束语句,一直递归调用方法,导致栈帧过多、栈内存溢出

栈帧过大导致栈内存溢出。单个栈帧的所需要的内存超出了栈内存大小

public static void m4(){

m4();

}

java.lang.StackOverflowError

2.8 堆栈的区别是什么

栈内存一般会用来存储局部变量和方法调用,但堆内存是用来存储Java对象和数组的的。堆会GC垃圾回收,而栈不会。

栈内存是线程私有的,而堆内存是线程共有的。

两者异常错误不同,但如果栈内存或者堆内存不足都会抛出异常。

栈空间不足:java.lang.StackOverFlowError。

堆空间不足:java.lang.OutOfMemoryError。

2.9 介绍下方法区

方法区(Method Area)是各个线程共享的内存区域

主要存储类的信息、运行时常量池

虚拟机启动的时候创建,关闭虚拟机时释放

如果方法区域中的内存无法满足分配请求,则会抛出OutOfMemoryError: Metaspace

常量池

可以看作是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息

javap -v Application.class #查看字节码结构(类的基本信息、常量池、方法定义)

运行时常量池

常量池是 *.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址

2.10 直接内存

直接内存:并不属于JVM中的内存结构,不由JVM进行管理。是虚拟机的系统内存,常见于 NIO 操作时,用于数据缓冲区,它分配回收成本较高,但读写性能高。

举例:Java代码完成文件拷贝

常规IO的数据拷贝流程

NIO数据拷贝流程

2.11 总结

1)什么是程序计数器

线程私有的,每个线程一份,内部保存的字节码的行号。用于记录正在执行的字节码指令的地址。

2)你能详细地介绍Java堆吗

线程共享的区域:主要用来保存对象实例,数组等,内存不够则抛出OutOfMemoryError异常

组成:年轻代+老年代

年轻代被划分为三部分,Eden区和两个大小严格相同的Survivor区

老年代主要保存生命周期长的对象,一般是一些老的对象

Jdk1.7和1.8的区别

1.7中有有一个永久代,存储的是类信息、静态变量、常量、编译后的代码

1.8移除了永久代,把数据存储到了本地内存的元空间中,防止内存溢出

3)什么是虚拟机栈

每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个栈帧(stack Frame) ,对应着一次次的Java方法调用。一次方法的调用,就是栈帧入栈到出栈的过程。

每个线程运行时所需要的内存,称为虚拟机栈,先进后出

每个栈由多个栈帧(frame)组成,对应着每次方法调用时所占用的内存。栈帧对应的方法执行完后,栈会将该方法对应的栈帧弹出栈,释放内存

每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

4)垃圾回收是否涉及栈内存

垃圾回收主要指就是堆内存,不涉及栈内存,当栈帧弹栈以后,内存就会释放。

5)栈内存分配越大越好吗

未必,默认的栈内存通常为1024k,栈帧过大会导致线程数变少。

6)方法内的局部变量是否线程安全

如果方法内局部变量没有逃离方法的作用范围,它是线程安全的

如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全

7)什么情况下会导致栈内存溢出

栈帧过多导致栈内存溢出。典型问题:递归调用,没有结束语句,一直递归调用方法,导致栈帧过多、栈内存溢出

栈帧过大导致栈内存溢出。单个栈帧的所需要的内存超出了栈内存大小

8)堆栈的区别是什么

栈内存一般会用来存储局部变量和方法调用,但堆内存是用来存储Java对象和数组的的。堆会GC垃圾回收,而栈不会。

栈内存是线程私有的,而堆内存是线程共有的。

两者异常错误不同,但如果栈内存或者堆内存不足都会抛出异常。

栈空间不足:java.lang.StackOverFlowError。

堆空间不足:java.lang.OutOfMemoryError。

9)解释一下方法区

方法区(Method Area)是各个线程共享的内存区域

主要存储类的信息、运行时常量池

虚拟机启动的时候创建,关闭虚拟机时释放

如果方法区域中的内存无法满足分配请求,则会抛出OutOfMemoryError: Metaspace

10)介绍一下运行时常量池

常量池:可以看作是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息

当类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址

11)直接内存

并不属于JVM中的内存结构,不由JVM进行管理。是虚拟机的系统内存

常见于 NIO 操作时,用于数据缓冲区,分配回收成本较高,但读写性能高,不受 JVM 内存回收管理

参考 黑马程序员相关视频与笔记

相关推荐