「Java面试」什么是Java虚拟机,为什么要使用?

“什么是Java虚拟机,为什么要使用”。

最近一个1年Java开发经验的同学去面试阿里,遇到这个问题向我求助。

Hi,大家好,我是Mic,一个工作14年的Java程序员。

那么,这个问题,面试官希望考察什么呢?

Java虚拟机,是Java应用程序运行的平台。

很多初学者,第一步基本上都是学习怎么写代码,并没有关注Java代码所运行的平台。

因此,虽然写了几年代码,但是对Java本身的理解不够深刻,程序一旦出现问题,很难排查和解决。

面试官考察这个问题的出发点,我认为有三个

  • 了解求职者对于Java语言的理解深度,这个方面有助于提升代码编写的质量
  • 了解求职者对于JVM基础的掌握程度,良好的基础有助于快速解决GC问题、内存问题等
  • 考察求职者的潜质,一个对技术有热情的人,有助于更好的陪伴公司成长

所以,对于这个问题来说,我们只需要从JVM关键特性Write Once、Run Anywhere这个角度去切入解释就行了。

下面我们来看看高手应该怎么回答。

Java虚拟机是Java语言的运行环境。

之所以需要Java虚拟机,主要是为Java语言提供Write Once,Run Anywhere能力。

实际上,一次编写,到处运行这个能力本身是不可能实现的。因为不同的操作系统和硬件。

最终执行的指令会有较大的差异。

而Java虚拟机就是解决这个问题的,它能根据不同的操作系统和硬件差异,生成符合这个平台机器指令。

简单理解,它就相当于一个翻译工具,在window下,翻译成window可执行的指令,在linux下,

翻译成linux下可执行的指令。

除了这个因素以为,我认为自动回收垃圾这个功能也是原因之一,它让开发者省去了垃圾回收这个工作。

减少了程序开发的复杂性。

好了,今天的分享就到这里结束了

如果喜欢我的作品,记得点赞、收藏、关注!

需要高手面试文档(附赠大厂内部十万字面试文档)或者有不懂的技术面试题想咨询的小伙伴可以后台私信【Mic】或者评论区留言。

Java虚拟机(jvm)-简介

一、Java运行时虚拟机内存区域划分

1.元空间(Metaspace)

元空间(Metaspace)从java8开始替换掉了原来的方法区(Method Area)。相比方法区(Method Area)在元空间中各个项目会共享同样的class内存空间,能提高内存的利用率且更利于垃圾回收;另外元空间并不在虚拟机中,而是使用本地内存,因此元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小:

-XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。

-XX:MaxMetaspaceSize,最大空间,默认是没有限制的。

-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集。

-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

2.堆(Heap)

堆(Heap)是Java 虚拟机所管理的内存中最大的一块,被所有线程共享的区域在虚拟机启动时创建。堆里面存放的都是对象的实例(new 出来的对象都存在堆中)。

堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”。堆又可分为新生代和老年代(Tenured Gen),更细一点划分新生代有可分为Eden Space(伊甸园区),Survivor Space(幸存者区)。

Eden:新创建的对象就会在Eden Space(伊甸园区)。当GC机制执行后没有被引用的对象将会被kill掉,其他的会进入Survivor Space(幸存者区)。

Survivor:保存新生代GC后还存活的对象。

Tenured Gen:对象存活时间比较长,经过多次新生代的GC(默认是15次)如果还存活将进入Tenured Gen(老年代)。

3.虚拟机栈(vm stacks)

虚拟机栈是线程私有的,生命周期与线程相同。创建线程的时候就会创建一个java虚拟机栈。

每个方法被执行的时候都会同时创建一个栈帧(Stack Frame ①)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

栈帧又分为一下几个区域:局部变量表、操作数栈、动态连接、方法出口等。

如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常当扩展时无法申请到足够的内存时会抛出OutOfMemoryError 异常。

4.本地方法栈(Native Method Stack)

本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是非常相似的,其区别是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。本地方法栈区域也会抛出StackOverflowError 和OutOfMemoryError异常。

5.程序计数器(Programe Counter Register)

程序计数器(Programe Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器,其记录当前线程执行程序的位置,通过改变计数器的值来确定执行的下一条指令,比如循环、分支、方法跳转、异常处理,线程恢复都是依赖程序计数器来完成。

Java虚拟机多线程是通过线程轮流切换并分配处理器执行时间的方式实现的。为了线程切换能恢复到正确的位置,每条线程都需要一个独立的程序计数器,所以它是线程私有的。

如果线程正在执行的是一个Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie 方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在Java 虚拟机规范中没有规定任何OutOfMemoryError 情况的区域。

二、Java虚拟机参数说明

-Xms size

设置堆的初始大小(以字节为单位)。该值必须是1024的倍数且大于1 MB。附加字母k或K表示千字节,m或M指示兆字节,g或G指示千兆字节。

-Xmx size

设置堆内存的最大大小(以字节为单位),附加字母k或K表示千字节,m或M指示兆字节,g或G指示千兆字节。一般的服务端部署,-Xms和-Xmx设置为同样大小以避免每次GC后调整堆的大小。-Xmx 与-XX:MaxNewSize等效。默认值为物理内存的1/4。

-Xmn size

设置堆新生代大小(以字节为单位),附加字母k或K表示千字节,m或M指示兆字节,g或G指示千兆字节。-Xmn与-XX:NewSize等效。

堆的年轻代区域用于新对象。GC在该区域比在其他区域更频繁地进行。如果年轻一代的规模太小,那么将会进行大量的小型垃圾收集。如果大小太大,则只执行完整的垃圾收集,这可能需要很长时间才能完成。Oracle建议您将年轻代的大小保持在整个堆大小的一半到四分之一之间。

-Xss size

设置线程堆栈大小(以字节为单位)通常只有几百K。附加字母k或K表示KB,m或M表示MB,g或G表示GB。默认值取决于平台(如:Linux / x64(64位):1024 KB)。

-XX:PermSize size -XX:MaxPermSize size

设置永久区的初始空间和最大空间。也就是说,jvm启动时,永久区一开始就占用了PermSize大小的空间,如果空间还不够,可以继续扩展,但是不能超过MaxPermSize,否则会OOM。

-XX:PermSize size -XX:MaxPermSize size在Jdk1.8中已经被弃用,被-XX:MetaspaceSize size -XX:MaxMetaspaceSize size选项取代。

-XX:NewRatio

新生代和年老代的堆内存占用比例。

-XX CompressedClassSpaceSize size类指针压缩空间大小, 默认为1G,只有当-XX:+UseCompressedClassPointers开启了才有效。

Java虚拟机(Java Virtual Machine)详解

Java虚拟机(Java Virtual Machine,简称JVM)是一个能够执行Java字节码的虚拟计算机。

当您编译 Java 源代码时,会得到一个中间 Java 文件,称为 Java 类(.class文件)。 该类文件由表示抽象指令代码的字节码组成。 这些代码不可由任何计算机处理器直接执行。

要运行 Java 程序,需启动 JVM 并将类文件传递给 JVM。 JVM 提供许多服务,包括装入类文件和解释(执行)字节码。JVM 是提供运行 Java 应用程序的运行时环境的核心技术。保证Java程序能够在不同的操作系统和硬件架构上无缝执行。

  • 加载代码(Class Loader):JVM负责从硬盘或网络中加载Java类(.class文件),并将它们加载到内存中。加载的过程包括验证、解析、初始化等步骤。
  • 字节码验证:JVM对加载的字节码进行验证,确保字节码文件没有受到破坏,并且符合Java的语言规范,以避免安全问题。
  • 执行字节码:JVM通过解释执行或即时编译(JIT,Just-in-Time Compilation)将字节码转换为平台特定的机器码,执行Java程序。
  • 内存管理(垃圾回收):JVM负责管理堆内存和栈内存,并进行垃圾回收。它通过自动回收不再使用的内存,减少内存泄漏和溢出的风险。

类加载器(Class Loader):负责加载字节码文件并将其转换为类实例。类加载器是Java运行时的一个关键组件,它会根据不同的加载路径(如文件系统、网络等)加载类,并将其组织成类的层次结构。

运行时数据区: JVM的内存区域主要包括:

  • 方法区(Method Area):存储类的元数据(如类信息、常量池、静态变量等)。
  • 堆区(Heap):用于存放对象的内存区域,所有的对象实例和数组都在堆上分配。
  • 栈区(Stack):每个线程都有自己的栈,栈中存放方法的局部变量和操作数栈。每当一个方法被调用时,JVM会为其分配一个栈帧。
  • 程序计数器(PC Register):指示当前线程所执行的字节码的行号。

执行引擎(Execution Engine):负责执行字节码指令,包含:解释器(Interpreter):逐条解释执行字节码。即时编译器(JIT Compiler):将字节码编译为机器码,提升性能。

垃圾回收器(Garbage Collector):负责回收堆内存中不再使用的对象,自动管理内存,避免内存泄漏。

  • 跨平台JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行
  • 自动内存管理:JVM提供垃圾回收机制,自动管理内存分配和回收,减少了程序员的内存管理负担。
  • 安全性:JVM对字节码进行验证,能够有效避免恶意代码的执行,并且通过沙箱机制提供隔离环境。
  • JVM(Java Virtual Machine):是Java虚拟机,负责执行Java程序的字节码。
  • JRE(Java Runtime Environment):是Java运行时环境,包含JVM和运行Java程序所需的库和其他组件。JRE是开发者运行Java程序所需的环境。
  • JDK(Java Development Kit):是Java开发工具包,包含JRE和用于开发Java应用的工具(如编译器javac)。JDK是开发者开发Java程序所需要的完整环境。

本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。