模型
原理
概述
- JVM是一个运行Java字节码的虚拟计算机,可以在不同的平台上运行Java程序。
- JVM的主要功能是解释和执行Java字节码,将其转换为机器代码并执行。
- JVM是Java程序运行的核心组件,其工作原理涉及到类的加载、链接、初始化和执行等多个方面
阶段
- 加载阶段:
- JVM会在程序运行前加载需要执行的Java字节码文件,并转换为机器可以执行的代码。
- 在加载阶段,JVM会进行类的加载、链接和初始化。
- 其中类的加载包括查找类的字节码文件、读取类的字节码文件并存储在内存中,链接包括验证、准备和解析等操作,初始化则是执行类的静态代码块和静态变量的赋值。
- 运行阶段:
- JVM会根据程序的逻辑执行Java字节码,执行过程中会涉及到栈帧、堆区、方法区等内存区域。
- JVM会将字节码转换为机器码,并通过栈帧将执行信息存储在内存中,同时使用堆区存储对象实例和方法区存储类的信息。
- 卸载阶段:
- 当程序执行完毕或者出现异常时,JVM会对内存进行垃圾回收和资源释放,以保证程序的效率和稳定性。
- 在卸载阶段,JVM会对不再使用的对象进行垃圾回收,释放内存空间,同时关闭相关资源。
类加载
说明
- JVM类加载是指将Java程序中所引用的类文件加载到JVM中运行的过程。
- 当Java程序运行时,JVM会根据需要依次将类文件加载到内存中
- JVM类加载是Java程序运行的基本过程,它保证了Java程序能够正确调用和执行类的方法和属性。
- JVM类加载的过程分为三个阶段:加载、链接和初始化。
加载阶段
- 在加载阶段,JVM会查找并读取要执行的类文件,并将其加载到内存中。
链接阶段
连接过程又可分为三步:验证->准备->解析
- 验证主要是检查类文件是否符合Java语言规范和安全规范;
- 准备是为静态属性分配内存并设置默认值;
- 解析是将类文件中的符号引用解析为直接引用。这个阶段还包括将类与其他类和资源进行关联,并生成可执行代码。
注:符号引用(Symbolic Reference)是指用符号来描述所引用的目标,例如类或方法的名称、描述符等,而不直接指向目标的内存地址。符号引用在编译期间就已经确定,并在类文件的常量池中保存,它是一种动态连接,也就是在运行时才能确定所引用的目标。
直接引用(Direct Reference)是指直接指向目标的内存地址,也就是已经定位到目标的直接地址。在Java虚拟机的运行时数据区中,直接引用指向的是目标类或接口在方法区中的内存地址。
初始化阶段
- 在初始化阶段,JVM会对类进行初始化,即执行类的静态初始化代码块和静态变量初始化。这个阶段是在类第一次被使用时进行的。
类的生命周期
- 类从被加载到虚拟机内存中开始到卸载出内存为止,它的整个生命周期可以简单概括为 7 个阶段
双亲委派机制
- 在Java开发中,双亲委派机制是一种非常重要的机制,它能够保障Java程序的稳定性和安全性,减少代码冲突和混乱,提高程序的可维护性和可扩展性。
- 在Java中,每个类都必须被加载到内存中才能被使用。当Java程序需要使用一个类时,它会首先检查该类是否已经被加载。如果该类已经被加载,那么直接使用该类。如果该类没有被加载,那么Java程序会委托父类加载器去加载该类。如果父类加载器也没有加载该类,那么会继续往上委派,直到顶层的类加载器——启动类加载器(Bootstrap ClassLoader)。
- 通过双亲委派机制,Java程序可以避免重复加载同一个类,避免类的冲突和混乱,提高程序运行的稳定性。此外,双亲委派机制还可以确保程序的安全性,因为它可以防止恶意代码通过自定义类加载器来破坏系统安全。
GC
分类
部分收集((Partial GC)
- 新生代收集 (Minor GC / Young GC):只对新生代进行垃圾收集;
- 老年代收集 (Major GC / Old GC):只对老年代进行垃圾收集。
- 混合收集 (Mixed GC):对整个新生代和部分老年代进行垃圾收集。
整堆收集 (Full GC)
- 收集整个 Java 堆和方法区。
垃圾回收算法
说明
垃圾回收算法是一种自动化的内存管理技术,它会在程序运行时扫描堆内存中的对象,找出那些不再被程序使用的对象并将其释放,以防止内存泄漏和内存溢出
算法
- 标记-清除算法:首先会标记出所有被程序引用的对象,然后清除所有未被标记的对象。
- 复制算法:将堆内存划分为两个区域,每次只使用其中一个区域,当这个区域满了之后,将其中存活的对象复制到另一个区域,并清除原来的区域。
- 标记-整理算法:类似于标记-清除算法,但会在清除之后整理堆内存,使得剩余的对象都能够连续地占用一整块内存。
- 分代回收算法:根据对象的年龄将堆内存划分为几个代,每代对象存活的时间越久,其垃圾回收的频率越低。常用的是两代或三代回收算法。
- 增量式垃圾回收算法:将垃圾回收过程分成若干个阶段,每个阶段只处理一小部分的对象,以此来降低垃圾回收对程序运行的影响
内存泄漏
概述
- Java内存泄漏指的是在Java程序运行中,由于不当的内存管理,导致一些对象无法被垃圾回收机制及时释放,从而造成内存的浪费和泄漏,进而导致程序的性能下降或崩溃。
- 为了避免Java内存泄漏,需要注意及时清理所有不再使用的对象和引用,并且要对程序进行规范化的内存管理。
- 可以使用工具进行内存分析和检测,及时发现和修复内存泄漏问题。
可能的原因
- 静态变量的使用不当:静态变量会在内存中一直存在,如果没有及时释放,就会导致内存泄漏。
- 对象引用未及时清空:如果一个对象已经不再使用,但其引用仍然存在,就会导致该对象无法被垃圾回收,从而引发内存泄漏。
- 集合对象使用不当:如果在使用集合对象时,没有及时清理不再需要的元素,就会导致内存泄漏。
- 大对象的使用:如果程序中使用了大对象,但在使用完毕后没有及时清理,就会导致内存泄漏。
- 代码逻辑错误:如果程序中存在循环引用,或者在代码中出现死循环等问题,就会导致内存泄漏。
内存溢出
概述
- 内存溢出指的是程序在运行过程中申请的内存超过了系统分配给该程序的内存大小限制,导致程序无法再分配到足够的内存空间而崩溃或异常退出。
- 在编写程序时,需要注意内存使用情况,避免出现内存泄漏等问题,以确保程序的运行稳定和可靠。
原因
- 内存泄漏:程序在运行过程中无法释放已经申请的内存,导致内存空间被长期占用,最终导致内存溢出。
- 程序错误:程序中存在死循环、递归调用等问题,导致程序不断地申请内存,最终导致内存溢出。
- 数据量过大:程序处理的数据量较大,所需的内存空间超过了系统分配给该程序的内存大小限制,导致内存溢出。
避免措施
- 提高程序的内存利用率
- 优化程序设计,避免死循环、递归调用等问题。
- 合理管理内存,及时释放不需要的内存。
- 增加系统内存大小或者提高系统的性能,以满足程序的内存需求。