Java面试系列01:Java基础之JVM

参考链接:
JVM之内存结构详解
https://www.choupangxia.com/2019/10/18/jvm%E4%B9%8B%E5%86%85%E5%AD%98%E7%BB%93%E6%9E%84%E8%AF%A6%E8%A7%A3/

绪论

1.什么是Java虚拟机?
Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。
2.为什么Java被称作是“平台无关的编程语言”?
一般的高级语言如要在不同的平台上运行,至少需要编译成不同的目标代码。Java虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。而引入JVM后,Java语言在不同平台上运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。
3.jvm最大内存限制多少?
默认是物理内存的1/64,JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。

一、Java 类加载过程?

类加载器就是寻找类或接口字节码文件进行解析并构造JVM内部对象表示的组件。
在java中类装载器把一个类装入JVM,经过以下步骤:

  1. 加载:查找和加载Class文件。加载是类加载过程的一个阶段,这两个概念一定不要混淆。
  2. 链接:其中解析步骤是可以选择的
    (a)检查:检查载入的class文件数据的正确性
    (b)准备:给类的静态变量分配存储空间
    (c) 解析:将符号引用转成直接引用
  3. 初始化:对静态变量,静态代码块执行初始化工作

类的加载过程
当Java程序需要使用某个类时,如果该类还未被加载到内存中,JVM会通过加载、连接(验证、准备和解析)、初始化三个步骤来对该类进行初始化。当初始化一个类的时候, 如果发现其父类还没有进行过初始化, 则需要先触发其父类的初始化。

二、 描述一下 JVM 加载 Class 文件的原理机制?

类的加载:加载是类加载过程的一个阶段,这两个概念一定不要混淆。
在加载阶段, 虚拟机需要完成以下三件事情:

  1. 1)通过一个类的全限定名来获取定义此类的二进制字节流。
  2. 2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  3. 3)将类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说当程序中使用任何类时,系统都会为之建立一java.lang.Class对象, 作为方法区中这个类的各种数据的访问入口。

三、什么是类加载器,类加载器有哪些?

Java类加载器是Java运行时环境的一部分,负责动态加载Java类到Java虚拟机的内存空间中。
JVM中的类的加载器主要有三种:启动类加载器,拓展类加载器,应用类加载器。

  1. 启动类加载器(Bootstrap classLoader):又称为引导类加载器,由C++编写,无法通过程序得到。主要负责加载JAVA中的一些核心类库,主要是位于<JAVA_HOME>/lib/rt.jar中。
  2. 拓展类加载器(Extension classLoader):主要加载JAVA中的一些拓展类,位于<JAVA_HOME>/lib/ext中,是启动类加载器的子类。
  3. 应用类加载器System classLoader:又称为系统类加载器,主要用于加载CLASSPATH路径下我们自己写的类,是拓展类加载器的子类。

四、类加载器双亲委派模型机制?

双亲委派模型过程:某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

五、Java 内存分配?

先说说JVM内存结构,如图
Java面试系列01:Java基础之JVM
首先,JVM分为五个区域:栈(虚拟机栈、本地方法栈)、堆、方法区、程序计数器。

  • 栈:储存局部变量
  • 堆:一般情况下堆内存最大,堆存的是对象(new 出的对象)
  • 方法区:存储的是已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
  • 程序计数器:通过改变计数器的值来选取下一条字节码指令

下面说说对象运行过程中的内存分配(举例):

  1. 程序从 main 方法中进入;运行到 People p 时,在栈中开辟了一个空间;
  2. new Phone() 时,在堆中开了一个内存空间,此时会有一个内存值为 0x0001,p指向该地址;此时会找到对应的 People 的 class 文件,发现有三个变量和三个方法,于是将三个成员变量放在了堆中,但是此时的值为默认值。注意,在方法区里也有一个地址值,假设为 0x001,可以认为在堆中有一个方法区地址,通过在堆中的地址,可以找到方法区中相对应的方法;