本文主要是介绍面试 Java 基础八股文十问十答第二十四期,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
面试 Java 基础八股文十问十答第二十四期
作者:程序员小白条,个人博客
相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!
⭐点赞⭐收藏⭐不迷路!⭐
1)类加载与卸载
在Java中,类加载是指将类的字节码加载到内存中,并生成对应的Class对象的过程。类加载器负责加载类文件的任务,Java虚拟机(JVM)在运行时动态加载类,使得程序可以在运行时引用这些类。
类加载的过程包括加载、链接和初始化三个阶段:
- 加载(Loading): 将类的字节码从磁盘或网络加载到内存中。
- 链接(Linking): 将类与其他类连接起来,包括验证、准备(为静态变量分配内存并初始化为默认值)和解析(将符号引用转换为直接引用)。
- 初始化(Initialization): 执行类的初始化代码,包括静态变量赋值和静态代码块的执行。
类卸载是指当类在运行时不再需要时,由垃圾回收器将其从内存中删除的过程。类被卸载的条件是类加载器加载的类实例被回收,且该类所有的实例都已经被回收。类卸载是Java虚拟机的一个重要功能,可以避免内存泄漏和资源浪费。
2)JVM的内存模型
JVM的内存模型主要包括以下几个部分:
- 方法区(Method Area): 存放类的元信息、常量、静态变量等数据。方法区是线程共享的内存区域,用于存储被虚拟机加载的类信息。
- 堆(Heap): 存放对象实例。堆是线程共享的内存区域,用于存储所有被new出来的对象和数组。在堆中分为新生代和老年代,新生代又分为Eden区、Survivor From区和Survivor To区。
- 虚拟机栈(Java Virtual Machine Stacks): 每个线程在创建时会创建一个栈,用于存放局部变量、方法参数、返回值和部分结果。栈帧包含了方法的运行过程,包括局部变量表、操作数栈、动态链接、方法出口等信息。
- 本地方法栈(Native Method Stack): 与虚拟机栈类似,但是用于执行本地方法的部分。
- 程序计数器(Program Counter): 每个线程都有一个程序计数器,用于存储当前线程正在执行的字节码指令地址。
3)堆和栈的区别
堆和栈是Java中两种不同的内存分配方式,主要区别如下:
- 存放内容: 堆用于存放对象实例,包括由new创建的对象和数组。栈用于存放基本数据类型的变量和对象的引用(即对象的地址)。
- 生命周期: 堆中的对象的生命周期由虚拟机的垃圾回收器管理,当对象不再被引用时,会被垃圾回收器回收。栈中的变量生命周期与方法的调用周期相同,当方法执行结束时,栈中的局部变量会被销毁。
- 空间大小和管理: 堆的空间通常较大,可以动态地分配和回收内存。栈的空间相对较小,大小在编译时就已确定,并且由系统自动管理。
- 访问速度: 栈的访问速度比堆要快,因为栈是按照“先进后出”的原则管理数据,访问和存储速度更快。堆的访问速度相对较慢,因为要通过引用来访问对象。
总的来说,堆和栈在Java中扮演着不同的角色,理解它们的区别有助于更好地理解Java程序的运行机制和内存管理。
4)什么时候会触发 Full GC
Full GC(Full Garbage Collection)是Java虚拟机执行的一种垃圾回收操作,它会清理整个堆内存,包括新生代和老年代。Full GC通常在以下情况下触发:
- 老年代空间不足: 当老年代的空间不足以存放新分配的对象时,会触发Full GC来清理老年代,并尽量回收内存。
- 永久代(在Java 8之前)或元空间(在Java 8及以后)空间不足: 如果永久代或元空间的空间不足以存放类的元数据、常量池等信息时,会触发Full GC来进行清理。
- 手动触发: 开发人员可以通过调用
System.gc()
方法来建议虚拟机执行垃圾回收操作,有时候会触发Full GC。
Full GC是一种开销较大的操作,因为它会暂停所有的应用线程,直到垃圾回收完成。因此,应尽量避免Full GC的频繁发生,可以通过优化程序代码和合理设置堆内存大小来减少Full GC的次数。
5)什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?
Java虚拟机(Java Virtual Machine,JVM)是Java程序运行的环境,它负责将Java字节码解释或编译成特定平台上的机器指令,并管理程序的内存、线程等资源。JVM实现了Java语言规范,是Java跨平台特性的关键。
Java被称作“平台无关的编程语言”,主要是因为Java程序在编译时生成的是字节码(Bytecode),而不是特定平台上的机器码。这些字节码可以在任何支持Java虚拟机的平台上运行,而无需重新编译。Java虚拟机负责将字节码解释或编译成特定平台上的机器指令,从而实现了跨平台的能力。
6)Java内存结构
Java内存结构包括以下几个部分:
- 程序计数器(Program Counter Register): 每个线程都有一个程序计数器,用于存储当前线程正在执行的字节码指令地址。
- Java虚拟机栈(Java Virtual Machine Stacks): 每个线程在创建时都会创建一个栈,用于存放方法的局部变量、方法参数、返回值和部分结果。每个方法在执行时会创建一个栈帧,栈帧包含了方法的运行过程中所需的信息。
- 本地方法栈(Native Method Stack): 与虚拟机栈类似,但用于执行本地方法(Native Method)的部分。
- 堆(Heap): 存放对象实例,包括由
new
创建的对象和数组。堆是所有线程共享的内存区域,用于存储动态分配的对象。 - 方法区(Method Area): 存放类的元信息、常量、静态变量等数据。方法区是所有线程共享的内存区域,用于存储被虚拟机加载的类信息。
- 运行时常量池(Runtime Constant Pool): 方法区的一部分,用于存放编译期生成的字面量和符号引用。在运行时,还可以将新的常量池符号引用存放到运行时常量池中。
这些内存区域在Java程序的运行过程中起着不同的作用,相互配合来支持程序的执行。
7)对象分配规则
Java中的对象分配规则主要包括以下几个方面:
- 堆分配: Java中的对象实例都在堆(Heap)中分配内存。当我们使用
new
关键字创建一个对象时,内存会在堆上动态分配。 - 栈上分配: 对于一些不逃逸的局部变量,编译器可以选择将它们分配在栈上,这样可以提高对象的访问速度。
- 寄存器分配: 一些简单的对象可以直接存储在CPU的寄存器中,而不必分配在堆或栈上。
- 常量池中的分配: 字符串常量和基本类型的常量(如
int
、float
等)可以在常量池中分配内存。 - 线程本地分配缓冲区(TLAB): 为了提高多线程环境下的对象分配效率,JVM会为每个线程预先分配一块小的内存空间,称为线程本地分配缓冲区。
8)Java对象创建过程
Java对象的创建过程主要包括以下几个步骤:
- 类加载: 当我们第一次使用某个类时,Java虚拟机会加载并初始化该类。
- 内存分配: 一旦类被加载,JVM会在堆中分配内存给该对象。如果对象需要的内存大小在TLAB(线程本地分配缓冲区)中无法分配,则会在堆中进行分配。
- 初始化: 在分配内存后,JVM会对对象进行初始化,包括设置对象的默认值和调用构造方法。
- 构造方法执行: 构造方法会执行对象的初始化过程,初始化对象的各个字段。
- 对象引用: 最后,将对象的引用返回给调用方,调用方可以使用该引用来操作对象。
9)类的生命周期
类的生命周期包括以下几个阶段:
- 加载(Loading): 加载是指将类的字节码加载到内存中,并生成对应的Class对象的过程。加载阶段由类加载器完成,包括查找类的字节码文件、创建Class对象等。
- 链接(Linking): 链接阶段包括验证、准备和解析三个阶段:
- 验证(Verification): 确保加载的字节码符合Java虚拟机规范,并且不会危害虚拟机的安全。
- 准备(Preparation): 为类的静态变量分配内存,并设置默认初始值。
- 解析(Resolution): 将类中的符号引用转换为直接引用。
- 初始化(Initialization): 初始化阶段是类加载的最后一步,它会执行类的初始化代码,包括静态变量赋值和静态代码块的执行。类的初始化是在必要时才进行的,例如当访问类的静态成员或调用静态方法时。
- 使用(Usage): 类初始化完成后,可以通过创建对象、访问静态成员等方式来使用类。
- 卸载(Unloading): 类卸载是指当类不再被引用且满足垃圾回收条件时,由垃圾回收器将其从内存中删除的过程。类的卸载是Java虚拟机的一个重要功能,可以避免内存泄漏和资源浪费。
10)简述Java的对象结构
Java的对象结构主要包括对象头(Object Header)、实例数据(Instance Data)和对齐填充(Padding)三部分:
- 对象头(Object Header): 对象头存储了对象的元数据信息,包括对象的哈希码、GC分代年龄、锁状态标志、线程持有的锁信息等。对象头的大小在不同的JVM实现中可能有所不同。
- 实例数据(Instance Data): 实例数据存储了对象的各个字段的值,包括实例变量和从父类继承的变量。
- 对齐填充(Padding): 对齐填充是为了保证对象在内存中的地址是8字节对齐的,以提高访问速度。对齐填充会在对象的实例数据和对象头之间插入一些无意义的填充数据,使得对象的大小为8字节的整数倍。
Java对象的结构在不同的JVM实现中可能有所不同,但通常都包括上述三部分。对象的大小取决于对象头的大小、实例数据的大小和对齐填充的大小。
开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system
前后端总计已经 900+ Star,1.5W+ 访问!
⭐点赞⭐收藏⭐不迷路!⭐
这篇关于面试 Java 基础八股文十问十答第二十四期的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!