Java虚拟机JVM常见面试题记录

1. 运行时数据区

在Java虚拟机(JVM)中,运行时数据区可以分为以下几个部分:

  1. 方法区(Method Area):也叫静态区,用于存储类的结构信息、常量、静态变量以及编译器生成的代码等数据。

  2. (Heap):用于存储对象和数组实例,其大小可以动态地调整。

  3. Java栈(Java Stack):每个线程都会有一个Java栈,用于存储方法执行时的局部变量、操作数栈、方法出口等信息。

  4. 本地方法栈(Native Method Stack):与Java栈的作用类似,但是用于执行本地方法,它不属于虚拟机规范,具体实现可以依赖于操作系统。

  5. 程序计数器(Program Counter Register):存储当前线程正在执行的指令地址,即下一条指令的地址。

除了上述这些,JVM还可以通过直接内存(即使用Native内存)来扩展堆以外的内存,从而提高JVM执行效率。

其中,线程私有的包括:程序计数器、Java栈、本地方法栈;线程共享的包括:堆、方法区。

2. 垃圾回收算法

Java虚拟机的垃圾回收主要使用的是基于分代的垃圾回收算法,也就是把对象分为几代,每一代使用不同的回收算法。

扫描二维码关注公众号,回复: 15511076 查看本文章
  1. 标记-清除算法(Mark-and-Sweep):首先遍历所有的对象,标记出所有需要回收的对象,然后统一回收所有标记的对象。该算法会产生不连续的内存碎片,不利于内存分配。

  2. 标记-整理算法(Mark-and-Compact):与标记-清除算法不同,该算法在标记出需要回收的对象后,会先对存活的对象进行整理,将他们紧凑排列,然后全部向一端移动,这样可以消除内存碎片问题。

  3. 复制算法(Copying):将内存分为两块,每次只使用其中的一块,在回收时将正在使用的内存中存活的对象复制到未使用的内存块中,然后清除正在使用的内存块中的所有对象。该算法容易产生空间浪费。

  4. 分代回收算法(Generational Collection):将Java堆划分为新生代和老年代,新生代中存活时间短的对象会被快速回收,使用复制算法;老年代中存货时间长的对象会暂时存放在内存中,较长一段时间后才会被回收,使用标记-整理算法。

Java虚拟机根据当前应用的性质和系统的特点选择垃圾回收算法的组合。目前大多数JVM采用的是分代回收算法,即在新生代使用复制算法,在老年代使用标记-整理算法。

3. 垃圾回收器

垃圾回收器是Java虚拟机的一部分,用于自动回收系统中的无用对象占用的内存空间。常见的垃圾回收器包括:

  1. Serial收集器:是单线程的垃圾回收器,使用标记-复制算法或标记-整理算法进行垃圾回收。适用于小型应用程序和客户端程序。

  2. Parallel收集器:多线程的垃圾回收器,使用标记-整理、标记-复制和分代回收等算法。适用于需要大量内存进行垃圾回收的服务器应用程序。

  3. CMS收集器:使用标记-清除和标记-整理算法,主要用于对于响应时间敏感的应用程序,采用并发垃圾回收方式,减少应用程序的停顿时间。

  4. G1收集器:使用标记-整理算法,根据应用程序实时状态来决定哪些内存块需要进行回收,使得程序响应时间更加稳定。

此外,还有一些垃圾回收器,如ZGC、Shenandoah等,是最近Oracle和RedHat推出的实现长时间垃圾回收的垃圾收集器,可以在多核处理器上实现并行收集和压缩,提供短暂的停顿时间,并支持大型的堆内存。

4. 类的加载过程

Java虚拟机在使用类的时候,需要完成以下的类的加载过程:

  1. 加载(Loading):查找并加载类的二进制数据。在该阶段,虚拟机会找到类的字节码文件并加载到内存中,为此JVM需要完成三件事情:通过一个类的全限定名字来获取定义此类的二进制字节流;将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;在堆中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问入口。

  2. 验证(Verification):确保被加载的类的正确性。在该阶段,虚拟机会对加载的字节码进行校验,以保证其符合JVM规范。

  3. 准备(Preparation):为类的静态变量分配内存,并将其初始化为默认值。在该阶段,虚拟机会为类变量分配内存并设置默认初始值(0或null)。

  4. 解析(Resolution):将常量池中的符号引用替换为直接引用。在该阶段,虚拟机会将常量池中的符号引用替换为直接引用。

  5. 初始化(Initialization):为类的静态变量赋予正确的初始值。在该阶段,虚拟机会执行类构造器()方法,为类的静态变量赋值(JVM保证了该方法在多线程环境下正确的执行)。

  6. 使用(Using):通常在该阶段完成类的实例化。

  7. 卸载(Unloading):当JVM判断该类实例已经不再被引用时,释放该类所占用的内存空间。

需要注意的是,这七个阶段并不是一步一步的,在加载过程中,有部分阶段可以一起完成,或者同时被执行。而在实际的虚拟机实现中,为了性能和实用性,有些阶段也可以和其它的阶段交叉进行。

5. 类加载器

在Java虚拟机中,类加载器用于加载Java类的字节码文件到JVM中,并生成Java类的Class对象。Java虚拟机中的类加载器主要有以下几种:

  1. 启动类加载器(Bootstrap Class Loader):也叫根加载器,是Java虚拟机内置的类加载器,用于加载Java核心类库,例如Object、System等各种基础类和原生类型的类。

  2. 扩展类加载器(Extension Class Loader):用于加载Java平台的扩展类,例如Java虚拟机类库扩展目录(System.getProperty(“java.ext.dirs”))中的类。

  3. 应用程序类加载器(Application Class Loader):是用于加载应用程序的类,也称为系统类加载器,它会依据Java应用程序的类路径(classpath)搜索要加载的类文件。

  4. 自定义类加载器:Java程序员可以自定义类加载器,以满足自己特定的需求,例如实现热部署机制、隐藏类的真实位置等。

双亲委派机制

当类加载器需要对一个Java类进行加载时,它会通过委托机制(Delegation Model)来搜索和加载类型。委托机制的基本思想就是由上至下进行类的加载,即首先判断当前类是否被上层加载器加载过,如果是则直接使用该类;否则,将该加载请求委托给父类加载器进行处理,因此所有的类加载器最终都会被委托给根加载器处理。这样一来,便形成了一颗类加载器层次树。

沙箱安全机制

Java的沙箱安全机制是指在Java虚拟机中为Java应用程序创建一个安全的执行环境,包含以下几个方面:

  1. 类装载限制:Java虚拟机使用类装载器来装载类的字节码文件,类装载器会检查类文件的数字签名以及访问权限等信息,从而在类装载阶段限制了动态修改类字节码等一些潜在的危险操作。

  2. 安全管理器(Security Manager):Java平台提供了安全管理器,通过安全管理器,可以控制Java应用程序的访问权限,包括对文件系统、网络、系统资源等的访问限制。

  3. 字节码校验:Java虚拟机会在类装载的时候对字节码进行校验,验证字节码的合法性和安全性,拦截危险代码。

  4. 线程管理:Java虚拟机中的线程是受控的,线程的启动、中断、休眠等操作都要受到安全管理器的限制和验证。

  5. 垃圾回收:Java虚拟机中的垃圾回收机制能够自动地回收从Java应用程序中创建的对象内存,避免了危险的随意内存释放操作。

总之,Java的沙箱安全机制提供了一套基于类装载机制、安全管理器、字节码校验、线程管理和垃圾回收的安全方案,从而保证了Java应用程序的安全性,防止了恶意操作,提高了Java程序的可靠性和稳定性。

猜你喜欢

转载自blog.csdn.net/weixin_43598687/article/details/131399913