有没有专门的销售公司,海外seo,网站开发步奏,wordpress post meta在Java开发领域#xff0c;JVM面试一直是一个热门话题。作为一名优秀的开发者#xff0c;你是否已经准备好迎接这场挑战了呢#xff1f;今天#xff0c;我们就来深度解析一下JVM面试的热点问题#xff0c;帮助你更好地应对面试#xff0c;一举拿下offer#xff01;
1、…在Java开发领域JVM面试一直是一个热门话题。作为一名优秀的开发者你是否已经准备好迎接这场挑战了呢今天我们就来深度解析一下JVM面试的热点问题帮助你更好地应对面试一举拿下offer
1、说一下 JVM 的主要组成部分及其作用 JVM包含两个子系统和两个组件两个子系统为Class loader(类装载)、Execution engine(执行引擎)两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)。
Class loader(类装载)根据给定的全限定名类名(如java.lang.Object)来装载class文件到 Runtime data area中的method area。Execution engine执行引擎执行classes中的指令。Native Interface(本地接口)与native libraries交互是其它编程语言交互的接口。Runtime data area(运行时数据区域)这就是我们常说的JVM的内存。
作用
在Java程序的执行过程中首先会通过编译器将Java源代码转换成一种叫做字节码Bytecode的中间形式。这种字节码是一种平台无关的二进制代码它比Java源代码更接近于机器语言但仍然包含了一些用于定位和操作数据结构的指令。
然后类加载器ClassLoader会负责将这种字节码加载到内存中。这个过程通常是动态进行的也就是说当程序需要使用某个类的时候类加载器就会将这个类的字节码加载到内存中。这个过程通常发生在Java虚拟机JVM的运行时数据区Runtime Data Area的方法区内。
需要注意的是虽然字节码文件是JVM的一套指令集规范但它并不能直接交给底层操作系统去执行。这是因为不同的操作系统可能对同一组字节码有不同的解释方式因此需要一个专门的命令解析器执行引擎Execution Engine来将字节码翻译成底层系统可以执行的指令。
最后Java程序中还可以调用其他语言编写的本地库接口Native Interface进行一些系统调用或者C函数调用。这种方式可以使Java程序更好地利用底层系统的功能提高程序的性能和效率。
下面是ava程序运行机制详细说明
Java程序运行机制步骤
首先利用IDE集成开发工具编写Java源代码源文件的后缀为.java再利用编译器(javac命令)将源代码编译成字节码文件字节码文件的后缀名为.class运行字节码的工作是由解释器(java命令)来完成的。 从上图中可以观察到Java文件经过编译器的处理后被转换成了对应的.class文件。接下来类加载器会负责将这些.class文件加载到Java虚拟机JVM中。
实际上类的加载过程可以用一句话来概括类的加载是将类的二进制数据从.class文件中读取出来并将其放入内存中的运行时数据区的方法区内。然后在堆区创建一个java.lang.Class对象用于封装类在方法区内的数据结构。
通过类加载器的作用JVM能够动态地加载和卸载类使得程序可以在运行时动态地获取和使用类。这种动态性是Java语言的一大特点它赋予了程序更高的灵活性和扩展性。
2、说一下JVM运行时数据区
Java虚拟机在执行Java程序的过程中会将其管理的内存区域划分为多个不同的数据区域。每个数据区域都有特定的用途并且它们的创建和销毁时间也不同。
首先Java虚拟机将内存区域划分为堆Heap、方法区Method Area和栈Stack。 堆堆是Java虚拟机所管理的最大的数据区域。它用于存储对象实例以及数组。当创建一个新的对象时会在堆上分配相应的内存空间。而当一个对象不再被引用时垃圾回收器会负责将其所占用的内存释放回堆中。堆的大小可以通过JVM的参数进行设置例如-Xmx和-Xms分别表示最大堆大小和初始堆大小。 方法区方法区是用于存储类信息、常量池、静态变量等数据的一块内存区域。它与Java类相关联因为每个Java类都包含方法区的一份拷贝。方法区的生命周期与Java虚拟机的生命周期一致因此随着虚拟机进程的启动而存在。 栈栈是Java虚拟机用来支持函数调用和方法执行的数据结构。每个线程在创建时都会创建一个独立的栈其中存储着局部变量、操作数栈和返回地址等信息。栈的特点是后进先出LIFO即最后进入栈的元素会最先被取出。栈的生命周期与线程的生命周期一致因此依赖于线程的启动和结束来建立和销毁。
除了这些主要的数据区域外Java虚拟机还可能划分其他一些辅助的区域例如程序计数器Program Counter Register和本地方法栈Native Method Stack等。这些区域的具体用途和生命周期取决于Java虚拟机的实现和运行环境。
程序计数器Program Counter Register当前线程所执行的字节码的行号指示器字节码解析器的工作是通过改变这个计数器的值来选取下一条需要执行的字节码指令分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成本地方法栈Native Method Stack与虚拟机栈的作用是一样的只不过虚拟机栈是服务 Java方法的而本地方法栈是为虚拟机调用 Native 方法服务的 3、什么是堆内存?
以Hotspot为例堆内存HEAP主要由GC模块进行分配和管理 可分为以下部分
新生代(伊甸园区幸存者区)老年代
我们在jvm参数中只要使用-Xms-Xmx等参数就可以设置堆的大小和最大值理解jvm的堆还需要知道下面这个公式 堆内内存 新生代老年代。如下面的图所示 在使用堆内内存on-heap memory的时候完全遵守JVM虚拟机的内存管理机制采用垃圾回收器GC统一进行内存管理GC会在某些特定的时间点进行一次彻底回收也就是Full GCGC会对所有分配的堆内内存进行扫描在这个过程中会对JAVA应用程序的性能造成一定影响还可能会产生Stop The World。 常见的垃圾回收算法主要有
引用计数器法Reference Counting标记清除法Mark-Sweep复制算法Coping标记压缩法Mark-Compact分代算法Generational Collecting
4、什么是堆外内存
堆外内存也常被称为直接内存是Java虚拟机管理内存的一种方式。与Java虚拟机的堆内存相对应堆外内存是将内存对象分配在Java虚拟机的堆以外的内存区域。这部分内存并不受Java虚拟机的管理而是直接由操作系统进行操作和管理。
这种设计的主要优点是能够在一定程度上减少垃圾回收对应用程序造成的影响。因为堆外内存的分配和释放不依赖于Java虚拟机的垃圾回收机制所以它可以更快速地进行内存的分配和释放从而提高应用程序的性能。
作为Java开发者我们经常使用java.nio.DirectByteBuffer类来管理堆外内存。这个类的实例会在对象创建的时候自动分配堆外内存。DirectByteBuffer类提供了一种在Java堆外分配内存的方式它主要是通过其成员变量unsafe来进行操作的。
5、使用堆外内存的优点
减少了垃圾回收 因为垃圾回收会暂停其他的工作。加快了复制的速度堆内在flush到远程时会先复制到直接内存非堆内存然后在发送而堆外内存相当于省略掉了这个工作。
6、简述Java垃圾回收机制
在Java编程中程序员并不需要显式地释放对象的内存这是由Java虚拟机JVM自动完成的。当一个对象不再被任何变量引用时它就会被视为“垃圾”并被标记为可回收的内存。然后JVM会定期运行垃圾回收线程来检查这些垃圾对象并将它们从内存中清除。
这个垃圾回收线程在JVM中的优先级是低的这意味着它不会在程序运行过程中频繁地执行。相反它会在JVM认为合适的时候执行。例如当JVM的空闲时间超过一定阈值时或者当堆内存的使用率达到一定限制时垃圾回收线程就会被触发。
垃圾回收线程的工作过程是这样的首先它会扫描所有的对象找出那些没有被任何其他变量引用的对象。这些对象就被称为“垃圾”。然后它将这些垃圾对象添加到一个称为“垃圾回收集合”的数据结构中。最后它会从内存中彻底清除这些垃圾对象释放它们占用的内存空间。
总的来说Java程序员不需要担心内存管理问题因为JVM会自动处理这些问题。这大大简化了编程的复杂性使得程序员可以更专注于实现具体的功能而不是管理内存。
7、哪些对象会被存放到老年代
新生代对象每次经历⼀次minor gc年龄会加1当达到年龄阈值默认为15岁会直接进⼊老年代大对象直接进⼊老年代新生代复制算法需要⼀个survivor区进行轮换备份如果出现大量对象在minor gc后仍然存活的情况时就需要老年代进行分配担保让survivor⽆法容纳的对象直接进⼊老年代如果在Survivor空间中相同年龄所有对象大⼩的总和大于Survivor空间的⼀半年龄大于或等于该年龄的对象就可以直接进⼊年⽼代。
8、什么时候触发full gc
调用System.gc时系统建议执行Full GC但是不必然执行老年代空间不⾜方法区空间不⾜通过Minor GC后进入老年代的平均大小大于老年代的可用内存由Eden区、From Space区向To Space区复制时对象大小大于To Space可用内存则把该对象转存到老年代且老年代的可用内存小于该对象大小