1.1JDK、JRE、JVM的关系是什么?
Java Development Kit(JDK)是Java开发工具包,包含了Java编译器、Java虚拟机(JVM)、Java类库等工具。
Java Runtime Environment(JRE)是Java运行时环境,包含了Java虚拟机(JVM)和Java类库。
Java Virtual Machine(JVM)是Java程序的运行环境,它负责将Java源代码编译成可执行的字节码文件,并在运行时解释执行这些字节码文件。
2.2JVM的内存模型以及分区情况和作用
JVM(Java虚拟机)的内存模型是基于垃圾回收算法实现的,它将Java程序运行时所需的内存划分为不同的区域,包括以下几个部分:
- 方法区(Method Area):用于存储已被加载的类信息、常量、静态变量等数据。该区域采用类似于文件系统的结构进行存储,每个类的信息都被存储在单独的文件中。
- 堆(Heap):用于存储对象实例和数组等动态分配的内存。堆是可扩展的,并且在运行时可以根据需要进行自动垃圾回收。
- 栈(Stack):用于存储方法的调用和返回信息、局部变量等数据。栈是线程私有的,每个线程都有自己的独立栈空间。
- PC寄存器(Program Counter Register):用于保存当前线程正在执行的指令地址。
JVM的分区情况如下:
- 方法区和堆:这两个区域是JVM最重要的内存区域,也是Java程序员最容易操作的内存区域。
- 本地方法栈(Native Method Stack):用于存储本地方法的调用信息,与Java代码无关。
- PC寄存器:用于保存当前线程正在执行的指令地址,与Java代码有关。
JVM的作用是提供一个平台无关的运行环境,使得Java程序可以在不同的操作系统和硬件平台上运行。同时,JVM还提供了垃圾回收机制,可以自动管理内存,避免了内存泄漏等问题。
1.3 JVM对象创建步骤流程是什么?
- 加载类文件:Java程序中使用到的类都是通过类加载器(Class Loader)来实现的。当Java程序需要使用某个类时,会首先查找该类所在的路径(即类的全限定名),如果找到了该类,就会将其加载到内存中。这个过程称为加载(Loading)。
- 验证字节码:在类被加载后,JVM会对类的字节码进行验证。这个过程包括语法检查、语义检查、符号引用验证等。如果字节码没有通过验证,则会抛出 ClassNotFoundException 异常。
- 解析字节码:在字节码验证通过后,JVM会将字节码转换为本地代码,这个过程称为解析(Parsing)。
- 初始化静态变量:在类被初始化为实例对象之前,其中的静态变量会被赋予默认值。这个过程称为静态变量初始化(Static Variable Initialization)。
- 分配内存:在类被初始化为实例对象之后,JVM会为其分配内存空间。在堆区中分配内存是Java程序中最耗时的操作之一,因此JVM提供了一些内存分配策略来提高性能。
- 设置实例变量:在为实例对象分配内存后,JVM会对其实例变量进行赋值。这个过程称为实例变量初始化(Instance Variable Initialization)。
- 调用构造方法:在完成实例变量的初始化后,JVM会自动调用该类的构造方法,以初始化实例对象的状态。如果该类没有定义构造方法,则会抛出 NoSuchMethodException 异常。
- 执行同步代码块:如果该实例对象是线程安全的,JVM会在运行时对其进行同步处理。这个过程称为同步代码块执行(Synchronized Block Execution)。
- 返回对象引用:最后,JVM会返回对新创建的对象的引用,以便程序可以使用它。
1.4垃圾回收算法有几种类型?他们对应的优缺点又是什么?
Java中的垃圾回收算法有以下几种类型:
- 标记-清除算法(Mark-Sweep):标记阶段会标记所有需要回收的对象,然后在清除阶段将这些对象释放掉。该算法的优点是简单高效,缺点是在清理后可能会产生堆碎片。
- 复制算法(Copy):复制算法将内存分为两个相等的区域,每次只使用其中一个区域,当这个区域用尽时将存活的对象复制到另一个区域中继续使用。该算法的优点是可以解决堆碎片问题,缺点是需要浪费一半的内存空间。
- 标记-整理算法(Mark-Compact):标记阶段会标记所有需要回收的对象,然后在整理阶段将存活的对象移动到堆的一个连续的未使用的区域中。该算法的优点是不需要额外的空间来存储复制后的存活对象,缺点是需要进行两次标记和整理操作,性能开销较大。
- 分代收集算法(Generational Collection):根据对象的生命周期将内存分为不同的代,一般分为年轻代和老年代。年轻代采用复制算法,老年代采用标记-清除或标记-整理算法。该算法的优点是可以降低垃圾回收对整个应用程序的影响,缺点是需要额外的空间来存储复制后的存活对象。
- CMS收集器(Concurrent Mark Sweep):与标记-清除算法类似,但多线程并发执行标记和清除操作,可以减少停顿时间。该算法的优点是可以在低停顿时间内完成垃圾回收,缺点是对CPU资源的使用比较高。
- G1收集器(Garbage First):将内存分成多个大小相等的Region,通过Region之间的垃圾回收来实现全局的垃圾回收。该算法的优点是可以减少停顿时间和GC日志输出,缺点是需要更多的内存空间来存储Region。
1.5介绍一下什么是类加载机制?
类加载机制是指Java虚拟机(JVM)如何将类文件加载到内存中并解析为Class对象的过程。Java中的类加载机制包括三个阶段:加载、链接和初始化。
- 加载阶段:JVM按照指定的类路径搜索类文件并将其读入内存,这个过程称为加载(Loading)。类路径包括当前目录、系统目录和用户目录等。
- 链接阶段:JVM在加载类的过程中会进行验证、准备和解析等操作,这个过程称为链接(Linking)。其中,验证是为了保证类的正确性,准备是为了完成符号引用的操作,解析是为了将符号引用转化为直接引用。
- 初始化阶段:JVM对已加载的类进行初始化处理,这个过程称为初始化(Initialization)。在初始化阶段,JVM会执行静态初始化代码块和静态变量赋值操作。如果没有静态初始化代码块和静态变量赋值操作,则默认执行空的静态初始化代码块。
总之,类加载机制是Java程序运行的基础,它保证了Java程序能够正确地找到和使用所需的类,并且保证了Java程序的安全性和可靠性。
1.7JVM预定义的类加载器有几种?
- 引导类加载器(Bootstrap ClassLoader):也称为启动类加载器,是JVM最顶层的类加载器。它负责加载JVM核心类库,如java.lang.*等。
- 扩展类加载器(Extension ClassLoader):也称为扩展类加载器,用于加载JVM扩展的类库和插件。它可以从classpath中搜索并加载jar包中的类。
- 系统类加载器(System ClassLoader):也称为系统类加载器,它属于扩展类加载器的子类,负责加载应用程序classpath之外的类。它是由操作系统负责管理的。
- 用户自定义类加载器(User-Defined ClassLoader):也称为自定义类加载器,用户可以自定义一个类加载器来加载特定的类或jar包。它可以通过实现ClassLoader接口来实现。
这些类加载器的作用如下:
- 引导类加载器:负责加载JVM核心类库,保证JVM正常运行。
- 扩展类加载器:用于加载JVM扩展的类库和插件,方便程序员进行二次开发。
- 系统类加载器:由操作系统管理,负责加载应用程序classpath之外的类,保证系统的安全性和稳定性。
- 用户自定义类加载器:允许程序员自定义一个类加载器来加载特定的类或jar包,增强了程序的灵活性和可维护性。
什么是双亲委派模式?有什么作用?
双亲委派模式(Parent Delegation Model)是Java类加载机制的一种设计模式。它的作用是将类的加载委托给父类加载器,在父类加载器无法完成加载任务时才由子类加载器来完成。
具体来说,双亲委派模式有以下特点:
- 第一次加载委托给父类加载器:当某个类需要被加载时,它的加载器会首先委托给它的父类加载器。如果父类加载器无法完成加载任务,才会由子类加载器来完成。
- 后续加载直接由子类加载器完成:如果父类加载器成功地加载了某个类,那么它的子类加载器就有权直接加载该类。不需要再次委托给父类加载器。
- 双亲委派原则:所有的类加载请求都必须经过双亲委派机制才能得到处理,只有双亲委派失败后,才会由子类加载器来尝试加载。
双亲委派模式的作用主要有以下几点:
- 保证Java类的安全性:通过双亲委派模式,可以避免不必要的类加载器操作,保证Java程序的安全性和可靠性。
- 避免重复加载和冲突:由于双亲委派模式保证了所有的类加载请求都必须经过双亲委派机制才能得到处理,因此可以避免重复加载和冲突的问题。
- 提高系统的扩展性:双亲委派模式的设计使得系统可以通过添加或删除类加载器来灵活地扩展和收缩应用程序。
JVM中垃圾收集器有哪些?他们特点分别是什么?
JVM中的垃圾收集器主要有以下几种:
- 标记-清除(Mark-Sweep)收集器:该收集器是最早出现的垃圾收集器,它通过标记-清除的方式来回收内存。它的优点是简单高效,缺点是在清理过程中会产生大量的不连续内存碎片。
- 复制(Copy)收集器:该收集器将内存分为两个相等的部分,每次只使用其中的一半,将存活的对象复制到另一半并进行标记。它的优点是可以避免内存碎片问题,缺点是需要浪费一半的内存空间。
- 标记-整理(Mark-Compact)收集器:该收集器也是通过标记-清除的方式来回收内存,但在清理过程中会将存活的对象移动到内存的一端并整理,从而避免了不连续内存碎片的问题。它的优点是效率高,缺点是需要消耗额外的空间来完成整理过程。
- 分代(Generational)收集器:该收集器根据对象的生命周期将堆分为不同的区域,根据不同区域的特点采用不同的收集策略。一般分为年轻代和老年代,年轻代采用复制或标记-整理的方式进行收集,老年代采用标记-清除或标记-整理的方式进行收集。它的优点是可以降低GC的频率和停顿时间,缺点是需要对堆进行分区和调整。
- CMS(Concurrent Mark Sweep)收集器:该收集器是一种以低停顿时间为目标的垃圾收集器,它采用了多线程并发标记和清理的方式来回收内存。它的优点是可以在应用程序运行的同时进行垃圾回收,缺点是可能会产生过多的碎片。
- G1(Garbage First)收集器:该收集器是一种基于分代的垃圾收集器,它将堆分为多个大小相等的Region,根据Region中存活对象的数量和大小来决定是否需要回收。它的优点是可以减少GC的频率和停顿时间,缺点是需要对堆进行分区和调整。
什么是Class文件?Class文件主要的信息结构有哪些?
Class文件是Java虚拟机(JVM)用来描述Java类和接口的二进制数据格式,它包含了被编译后的Java源代码信息、访问控制信息、常量池信息、字段信息、方法信息等内容。
Class文件主要的信息结构包括以下几个部分:
- 魔数(Magic Number):用于标识该文件为Class文件,其值为0xCAFEBABE。
- 版本号(Version Number):用于表示Java虚拟机版本,占用4个字节,后三位表示主版本号,前两位表示次版本号。
- 常量池(Constant Pool):用于存储类和接口中定义的常量和符号引用。
- 访问控制符(Access Flags):用于描述类或接口的访问权限,包括public、protected、default、private等。
- 类名(Class Name):用于描述当前Class文件所代表的Java类或接口的名称。
- 父类名(Superclass Name):用于描述当前Class文件所继承的父类的名称,如果当前类没有继承任何父类则为null。
- 接口列表(Interfaces):用于描述当前Class文件实现的所有接口的名称。
- 字段表(Fields):用于描述当前Class文件中声明的所有字段的属性信息,包括字段名、类型、修饰符等。
- 方法表(Methods):用于描述当前Class文件中声明的所有方法的属性信息,包括方法名、参数类型、返回值类型、修饰符等。