面试 JVM 八股文十问十答第六期

面试 JVM 八股文十问十答第六期

作者:程序员小白条个人博客

相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!

⭐点赞⭐收藏⭐不迷路!⭐

1)Java 是怎么实现跨平台的?

Java 实现跨平台的关键在于其"一次编写,到处运行"的特性,主要是通过以下几个方面实现的:

  • 字节码:Java 源代码经过编译器编译成字节码(bytecode),而不是机器码。字节码是与特定平台无关的中间代码。
  • Java 虚拟机(JVM):Java 虚拟机是 Java 跨平台的核心。它负责在不同平台上解释执行字节码。Java 程序在任何操作系统上都可以通过 JVM 运行,JVM 将字节码转换为特定平台的机器码执行。
  • Java 标准库:Java 提供了丰富的标准库,包括各种类和方法,这些标准库是跨平台的,无需重新实现。
  • 抽象的操作系统接口:Java 提供了一组抽象的操作系统接口(API),程序通过这些接口与底层操作系统进行通信,而不是直接调用操作系统特定的功能,从而保证了跨平台性。

2)编译执行和解释执行有什么区别?JVM 是哪个?

  • 编译执行:程序在运行之前先经过编译器编译成机器码,生成的机器码直接由计算机硬件执行。典型的编译型语言有 C、C++,其执行速度较快,但程序在不同平台上需要重新编译。
  • 解释执行:程序在运行时由解释器逐行解释成机器码并执行。典型的解释型语言有 Python、JavaScript,其执行速度较慢,但程序不需要重新编译,可以跨平台运行。

JVM(Java 虚拟机)是一种混合执行模式,它将 Java 源代码编译成字节码,然后在运行时由解释器逐行解释执行字节码,同时也具备即时编译(Just-In-Time Compilation,JIT)的能力,可以将频繁执行的字节码编译成本地机器码执行,提高执行效率。

3)JVM 内存区域是怎么划分的?

JVM 内存区域主要分为以下几个部分:

  • 程序计数器(Program Counter Register):用于存储当前线程执行的字节码指令地址,是线程私有的,每个线程都有一个独立的程序计数器。
  • Java 虚拟机栈(JVM Stack):用于存储方法执行的局部变量、操作数栈、动态链接、方法出口等信息。每个方法在执行时都会创建一个栈帧,栈帧在方法执行结束后会出栈。
  • 本地方法栈(Native Method Stack):类似于 Java 虚拟机栈,不过是为本地方法服务的。
  • Java 堆(Java Heap):用于存储对象实例和数组对象。堆是 JVM 所有线程共享的内存区域,也是垃圾回收器进行垃圾回收的主要区域。
  • 方法区(Method Area):存储类的结构信息、静态变量、常量、即时编译器编译后的代码等数据。在 Java 8 及之前版本中,方法区称为永久代(PermGen),从 Java 8 开始被元空间(Metaspace)所取代。
  • 运行时常量池(Runtime Constant Pool):方法区的一部分,用于存放编译期生成的字面量和符号引用。与类加载器的关系密切,属于方法区的一部分。
  • 直接内存(Direct Memory):不是 JVM 内存区域的一部分,但是与堆和方法区密切相关。JVM 中的 ByteBuffer 使用了直接内存,通过堆外内存访问来提高 I/O 效率。

JVM 内存区域的划分对 Java 程序的执行和垃圾回收都有着重要的影响。

4)Java 中堆和栈有什么区别?

在 Java 中,堆和栈是两种主要的内存分配区域,它们有以下区别:

  • 堆(Heap)
    • 用于存储对象实例和数组对象。
    • 是 JVM 所有线程共享的内存区域。
    • 由 Java 虚拟机的垃圾回收器进行管理和回收。
    • 对象的创建和销毁都在堆上进行,不受方法的作用域控制。
    • 堆内存的大小可以动态调整。
  • 栈(Stack)
    • 用于存储方法执行的局部变量、操作数栈、动态链接、方法出口等信息。
    • 是线程私有的,每个线程都有一个独立的栈。
    • 栈的大小在线程创建时就固定了,不可以动态调整。
    • 方法的调用和执行都在栈上进行,方法执行结束后局部变量会出栈,方法调用栈帧被销毁。

5)直接内存又是什么?

直接内存是指在 JVM 外部分配的内存空间,通常是通过调用本地方法库来分配内存,不受 Java 堆大小限制。在 Java 中,可以使用 NIO(New Input/Output)库中的 ByteBuffer 类来操作直接内存。

直接内存与 Java 堆的主要区别在于分配方式和使用方式:

  • 直接内存的分配不是通过 new 关键字来分配的,而是通过调用 ByteBuffer 的 allocateDirect() 方法来分配。
  • 直接内存的操作不是通过 JVM 来进行的,而是通过系统调用,因此可以绕过 Java 堆的限制,具有更高的性能。
  • 直接内存的释放不受 Java 垃圾回收器的管理,需要手动调用 ByteBuffer 的 clear() 方法来释放。

直接内存的主要优势在于提高了 I/O 操作的效率,特别是对于大量数据的读写操作,使用直接内存可以减少数据在 JVM 和操作系统之间的拷贝次数,提高了程序的执行效率。

6)Java 的常量池有听过吗?

是的,Java 的常量池是一种特殊的内存区域,用于存放编译期生成的字面量和符号引用。在 Java 中,常量池包括两种:类常量池和运行时常量池。

  • 类常量池:存放在编译期生成的字面量和符号引用,属于类的一部分,与类的字节码一起存放在 .class 文件中。
  • 运行时常量池:是方法区的一部分,用于存放类加载后生成的字面量和符号引用,是类加载过程中的一部分。

常量池的主要作用是节省内存空间和提高执行效率。在运行时,Java 虚拟机会将常量池中的字面量和符号引用解析成直接引用,以提高程序的执行效率。常量池还可以避免重复的字符串对象,提高了内存的利用率。

7)类加载器有了解过吗?

在 Java 中,类加载器(ClassLoader)是负责加载类文件并生成对应的 Class 对象的组件。类加载器通常按照一定的委派机制来加载类,它们可以动态加载类,从不同的来源加载类文件,如本地文件系统、网络等。Java 中的类加载器分为三种:

  • 启动类加载器(Bootstrap Class Loader):是最顶层的类加载器,负责加载 Java 核心类库,通常是由 JVM 实现并且是用 C++ 编写的,无法通过 Java 代码直接获取。
  • 扩展类加载器(Extension Class Loader):是用来加载 Java 平台的扩展库,位于 Bootstrap Class Loader 和 Application Class Loader 之间。
  • 应用程序类加载器(Application Class Loader):也称为系统类加载器,负责加载应用程序的类文件,是最常用的类加载器。

除了这三种标准类加载器,还可以通过继承 java.lang.ClassLoader 类来自定义类加载器,实现特定的类加载需求。

8)双亲委派能说说吗?

双亲委派(Parent Delegation)是 Java 类加载器的一种机制,它的基本原则是:当一个类加载器收到加载类的请求时,它首先不会尝试自己加载这个类,而是将加载请求委托给父类加载器去完成。只有当父加载器无法完成加载请求时,子加载器才会尝试加载类。

这种委派机制的好处是避免重复加载类,确保类的唯一性和一致性,同时也增强了安全性,防止恶意类替换。

9)JIT 知道是什么吗?

JIT(Just-In-Time)是一种动态编译技术,通常指的是在程序运行时将字节码即时编译成本地机器代码执行,以提高程序的执行效率。

在 Java 中,JIT 编译器是 Java 虚拟机的一部分,它能够监测到程序的热点代码(即经常执行的代码块),然后将其编译成本地机器代码,以取代解释执行,从而提高程序的运行速度。JIT 编译器通常在程序运行的早期会进行编译,以后会根据运行时的情况进行优化和重新编译。

10)AOT 呢?有听过吗?

AOT(Ahead-Of-Time)编译是一种在程序运行之前将源代码或中间代码编译成机器代码的技术。与 JIT 编译相反,AOT 编译是在程序运行之前就完成编译工作,生成的是与特定平台相关的本地机器代码,这样可以减少程序启动时的延迟。

在 Java 中,AOT 编译技术被称为 AOT 编译器,它可以将 Java 字节码编译成本地机器代码,然后保存在本地文件中。这样,在程序运行时就可以直接加载和执行本地机器代码,而不需要再进行解释或 JIT 编译,从而提高了程序的启动速度和执行效率。

开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system

前后端总计已经 1300+ Star,2W+ 访问!

⭐点赞⭐收藏⭐不迷路!⭐

相关推荐
ifanatic4 分钟前
[面试]-golang基础面试题总结
面试·职场和发展·golang
请你打开电视看看5 分钟前
Jvm知识点
jvm
程序猿进阶1 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
长风清留扬2 小时前
一篇文章了解何为 “大数据治理“ 理论与实践
大数据·数据库·面试·数据治理
jiao_mrswang2 小时前
leetcode-18-四数之和
算法·leetcode·职场和发展
Swift社区12 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
阿龟在奔跑12 小时前
引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
java·jvm·安全·list
王佑辉13 小时前
【jvm】方法区常用参数有哪些
jvm
王佑辉13 小时前
【jvm】HotSpot中方法区的演进
jvm
Dong雨13 小时前
力扣hot100-->栈/单调栈
算法·leetcode·职场和发展