JVM之内存区域划分、类加载、垃圾回收机制(GC)

JVM(Java虚拟机)是Java编程语言的核心组件之一,它是一个虚拟的计算机环境,用于在各种硬件和操作系统上执行Java字节码。JVM的设计目标是提供一种可移植、安全、高性能的执行环境,使得Java程序能够在不同平台上运行,而不受底层硬件和操作系统的限制。

为什么叫做虚拟机?

JVM被称为虚拟机,是因为它在物理硬件之上提供了一个虚拟的执行环境,它不是一个真实的硬件平台,而是在真实硬件之上的软件模拟。JVM会解释和执行Java程序的字节码,并在内存中模拟出Java程序运行所需要的各种环境和资源。

执行流程:

  1. 编写Java源代码:程序员编写Java程序的源代码,使用Java编译器将源代码编译成Java字节码文件(.class文件)。

  2. 类加载:当Java程序被运行时,JVM的类加载器会加载Java字节码文件到内存中,生成对应的类对象。

  3. 字节码解释和执行:JVM的执行引擎会解释和执行加载到内存中的字节码文件。它会逐条解释字节码指令,并在虚拟机中模拟执行这些指令,从而实现Java程序的功能。

  4. 即时编译(JIT Compilation):在一些情况下,JVM会将频繁执行的字节码编译成本地机器代码,以提高程序的执行效率。这个过程称为即时编译。

  5. 内存管理和垃圾回收:JVM负责管理内存的分配和释放,包括堆内存、栈内存、方法区等。它还通过垃圾回收器(Garbage Collector)来自动回收不再使用的内存对象,防止内存泄漏和溢出。

  6. 与本地代码交互:JVM还提供了本地方法接口(Native Interface),允许Java程序调用本地(即非Java虚拟机)的方法,以实现与底层系统的交互。

JVM内存划分

JVM(Java虚拟机)的内存划分是为了管理Java应用程序的内存使用,它将内存分为不同的区域,每个区域有不同的作用和生命周期。以下是JVM内存划分的主要区域:

  1. 堆内存(Heap Memory)线程共享:

    • 堆内存是Java应用程序运行时的主要内存区域。
    • 所有对象实例都存储在堆内存中。
    • 堆内存可以动态地增加或减少,用于存储Java对象和数组。
    • 堆内存分为新生代(Young Generation)、老年代(Old Generation)和永久代(PermGen,Java 8之前)或元空间(Metaspace,Java 8之后)等部分。
  2. 栈内存(Stack Memory)线程私有:

    • 栈内存用于存储线程执行方法时的局部变量、方法参数、返回值和部分方法调用的信息。
    • 每个线程都有自己的栈内存,用于存储线程私有的数据。
    • 栈内存中的数据在方法执行结束后会立即释放。
  3. 方法区(Method Area)线程共享:

    • 方法区用于存储类信息、静态变量、常量、编译器优化后的代码等。
    • 方法区在JVM启动时被创建,存储在堆内存中。
    • 方法区的大小取决于具体的JVM实现和运行时参数设置。
    • 在Java 8之前,方法区也被称为永久代(PermGen),而在Java 8及以后的版本中,方法区被替换为元空间(Metaspace)。
  4. 程序计数器(Program Counter)线程私有:

    • 程序计数器是每个线程私有的,用于存储当前线程正在执行的字节码指令的地址。
    • 程序计数器在多线程环境中起到了线程隔离的作用。
  5. 本地方法栈(Native Method Stack)线程私有:

    • 本地方法栈用于存储Java程序调用本地方法(即非Java虚拟机中的方法)时的数据。
    • 本地方法栈类似于栈内存,但是用于存储本地方法调用时的数据。

JVM类加载

类加载是Java虚拟机(JVM)在运行Java程序时将类文件加载到内存中并生成对应的类对象的过程。类加载是Java语言实现“一次编写,到处运行”的核心机制之一,它负责加载、连接和初始化类文件,以便Java程序能够正确地执行。

当Java虚拟机(JVM)加载类时,通常可以分为以下五个过程:

  1. 加载(Loading)

    • 加载是指查找并加载类文件的过程。在加载阶段,JVM通过类加载器(ClassLoader)根据类的全限定名(Fully Qualified Name)来定位并加载类文件。类加载器会将类文件加载到内存中,并生成对应的类对象。
    • 双亲委派模型

      • 启动类加载器(Bootstrap ClassLoader)

        • 启动类加载器是JVM的内置类加载器,它负责加载Java核心类库(如java.lang包中的类)和其他基础类库(如rt.jar中的类)。
        • 启动类加载器是用本地代码实现的,通常不是Java类,因此它不是继承自java.lang.ClassLoader
        • 启动类加载器没有父类加载器,它是类加载器层次结构的顶层。
      • 扩展类加载器(Extension ClassLoader)

        • 扩展类加载器是Java的标准扩展机制的一部分,它负责加载Java的扩展类库(如jre/lib/ext目录下的JAR包中的类)。
        • 扩展类加载器是sun.misc.Launcher$ExtClassLoader类的实例,它的父类加载器是启动类加载器。
      • 应用程序类加载器(Application ClassLoader)

        • 应用程序类加载器也称为系统类加载器,它负责加载应用程序类路径(Classpath)上的类。
        • 应用程序类加载器是sun.misc.Launcher$AppClassLoader类的实例,它的父类加载器是扩展类加载器。
      • 自定义类加载器

        • 自定义类加载器是由Java程序员编写的,用于加载特定路径下的类或者加载特定格式的类文件。
        • 自定义类加载器需要继承自java.lang.ClassLoader类,并覆盖findClass方法实现自定义的类加载逻辑。
        • 自定义类加载器可以在运行时动态地加载类,以实现一些特殊的需求,例如动态更新、热部署等。
    • 在双亲委派模型中,当一个类加载器收到加载类的请求时,它会先检查是否已经加载过这个类,如果没有加载过,就会依次委派给父类加载器去加载,直到顶层的启动类加载器。这样的设计保证了类加载的安全性和稳定性,同时避免了类的重复加载,提高了程序的性能和效率。
  2. 验证(Verification)

    • 验证阶段是确保类文件的正确性和安全性的过程。在这个阶段,JVM会对类文件进行各种验证,包括文件格式验证、字节码验证、符号引用验证和访问权限验证等。目的是防止恶意代码和不合法的类文件对系统造成安全风险。
  3. 准备(Preparation)

    • 准备阶段是为类的静态变量分配内存并设置默认初始值的过程。在准备阶段,JVM会为类的静态变量分配内存空间,并设置默认初始值,例如数值类型的变量设置为0,引用类型的变量设置为null。
  4. 解析(Resolution)

    • 解析阶段是将类中的符号引用转换为直接引用的过程。在解析阶段,JVM会将类、方法和字段等符号引用解析为直接引用,以便在程序运行时能够正确地定位到目标类、方法和字段。
  5. 初始化(Initialization)

    • 初始化阶段是类加载的最后一个阶段,在这个阶段,虚拟机执行类构造器(<clinit> 方法)的代码,对类的静态变量进行初始化。初始化阶段只有在真正使用类的时候才会触发,例如创建类的实例、调用类的静态方法或访问类的静态变量时。

JVM垃圾回收机制

ava的垃圾回收机制是基于自动内存管理的概念,它通过垃圾回收器(Garbage Collector)来自动识别和回收不再使用的内存对象,以避免内存泄漏和溢出。在Java中,垃圾回收器可以使用不同的垃圾回收算法来实现内存回收,以下是一些常见的垃圾回收算法以及它们在Java中的应用:

  1. 标记-清除算法(Mark and Sweep)

    • 标记-清除算法是最基本的垃圾回收算法之一,它分为两个阶段:标记阶段和清除阶段。
    • 在标记阶段,垃圾回收器遍历程序的对象图,标记所有可达对象。
    • 在清除阶段,垃圾回收器遍历堆内存,清除未被标记的对象,释放它们所占用的内存空间。
    • 标记-清除算法的缺点是会产生内存碎片,影响内存的连续分配。
  2. 复制算法(Copying)

    • 复制算法将堆内存分为两个区域:From空间和To空间。
    • 在垃圾回收过程中,所有存活的对象都会被复制到To空间,然后将From空间中的对象全部清除。
    • 复制算法解决了标记-清除算法中产生的内存碎片问题,但是需要额外的内存空间来进行复制操作。
  3. 标记-整理算法(Mark and Compact)

    • 标记-整理算法结合了标记-清除算法和复制算法的优点,它也分为标记阶段和整理阶段。
    • 在标记阶段,垃圾回收器标记所有可达对象。
    • 在整理阶段,垃圾回收器将存活的对象向一端移动,然后清除掉未被移动的对象,从而使得堆内存中的存活对象连续排列,不再产生内存碎片。

在Java中,垃圾回收器可以根据应用程序的需求选择不同的垃圾回收算法。Java的垃圾回收机制主要使用复制算法和标记-清除算法的组合,其中新生代内存通常使用复制算法,而老年代内存通常使用标记-清除算法或标记-整理算法。Java的垃圾回收器实现了自适应调节策略,根据应用程序的运行情况动态选择合适的垃圾回收算法和参数,以提高垃圾回收的效率和性能。

在Java的垃圾回收中,内存通常被划分为新生代(Young Generation)和老年代(Old Generation),它们有不同的特点和回收方式。

新生代(Young Generation):

  1. 特点

    • 新生代主要存放新创建的对象。
    • 新生代中的对象通常具有较短的生命周期。
    • 新生代通常采用复制算法来进行垃圾回收,将内存分为Eden空间、Survivor From空间和Survivor To空间。
  2. 回收方式

    • 新生代的垃圾回收通常是通过Minor GC(年轻代垃圾回收)来触发的。
    • 在Minor GC过程中,垃圾回收器会扫描Eden空间和Survivor空间,将存活的对象复制到Survivor To空间,并清除Eden空间和Survivor From空间中的垃圾对象。
    • 在多次Minor GC后,存活时间较长的对象会被晋升到老年代。

老年代(Old Generation):

  1. 特点

    • 老年代主要存放存活时间较长的对象。
    • 老年代中的对象通常具有较长的生命周期。
    • 老年代通常采用标记-清除算法或标记-整理算法来进行垃圾回收。
  2. 回收方式

    • 老年代的垃圾回收通常是通过Full GC(完全垃圾回收)来触发的。
    • 在Full GC过程中,垃圾回收器会扫描整个堆内存,对所有的对象进行标记、清除或整理,以回收内存空间。
    • Full GC过程会导致应用程序的停顿时间较长,因此尽量避免频繁触发Full GC是优化Java应用程序性能的重要目标之一。

新生代与老年代的转化方式:

  1. 晋升(Promotion)

    • 在新生代进行多次Minor GC后,存活时间较长的对象会被晋升到老年代。
    • 对象晋升到老年代的条件通常是达到一定的年龄阈值,例如通过对象的年龄计数器来判断。
  2. 直接分配到老年代(Direct Allocation to Old Generation)

    • 一些大对象或长期存活的对象可以直接分配到老年代,而不经过新生代的分配和晋升过程。
    • 直接分配到老年代的对象可能会增加老年代的内存压力,因此需要谨慎使用。

新生代与老年代的区别在于对象的生命周期和回收方式,新生代通常使用复制算法进行垃圾回收,而老年代通常使用标记-清除算法或标记-整理算法进行垃圾回收。对象在新生代和老年代之间的转化通常是通过晋升或直接分配的方式实现的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/589011.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AWS上面部署一台jenkins

问题 客户预算有限&#xff0c;需要在aws云上面搞一台EC2手动安装jenkins发版。 步骤 创建密钥对 在EC2服务里面创建密钥对&#xff0c;具体如下图&#xff1a; 设置密钥对&#xff0c;如下图&#xff1a; 保存好这个私钥文件&#xff0c;以便后续用这个私钥文件ssh登录j…

AI技术助推汽车行业走向更光明的未来

我们在汽车上度过的时间很多&#xff0c;有时候由于交通、天气和其他路况问题&#xff0c;我们在汽车上度过的时间之久甚至会出乎意料。正因如此&#xff0c;保障旅途体验的舒适和安全就显得至关重要。交通事故每天都会发生&#xff0c;因此在车辆中采取额外的安全措施对于所有…

强化基础-Java-泛型基础

什么是泛型&#xff1f; 泛型其实就参数化类型&#xff0c;也就是说这个类型类似一个变量是可变的。 为什么会有泛型&#xff1f; 在没有泛型之前&#xff0c;java中是通过Object来实现泛型的功能。但是这样做有下面两个缺陷&#xff1a; 1 获取值的时候必须进行强转 2 没有…

50位主播带货破亿,抖音3月榜单有哪些看点?

3月&#xff0c;随着“抖音商城38好物节”的开展&#xff0c;平台消费氛围浓郁。数据显示&#xff0c;2月28日至3月8日&#xff0c;平台日均支付GMV同比增长了33%&#xff0c;好物节电商直播累计时长达4327万小时&#xff0c;挂购物车的短视频看播量达760亿次。 不过&#xff0…

基于Zabbix 5.0 实现windows服务器上应用程序和主机端口的状态监控

基于Zabbix 5.0 实现windows服务器上应用程序和主机端口的状态监控 背景 用python开发的应用程序在服务器上运行,有时候会出现程序自动退出却收不到告警的情况 环境 zabbix服务器:Centos7 64位 Windows服务器: Windows 10 64位 软件 zabbix_server:zabbix5.0 zabbix_…

利用Winform实现文字滚动(仅供参考)

本人水平有限&#xff0c;如有写得不对的地方&#xff0c;望指正。为了简单化&#xff0c;做了一个简陋版的滚动控件。本文的内容仅供参考 测试环境&#xff1a; visual studio 2017 .net framework 4.0 原理非常简单&#xff1a; 1 先自定义一个继承UserControl的控件&am…

啥是MCU,MCU科普

啥是MCU&#xff0c;MCU科普 附赠自动驾驶学习资料和量产经验&#xff1a;链接 MCU是Microcontroller Unit 的简称&#xff0c;中文叫微控制器&#xff0c;俗称单片机&#xff0c;是把CPU的频率与规格做适当缩减&#xff0c;并将内存、计数器、USB、A/D转换、UART、PLC、DMA等…

数据恢复工具可以恢复所有丢失的文件吗

随着数字时代的快速发展&#xff0c;数据已经成为我们生活与工作中不可或缺的一部分。然而&#xff0c;数据丢失的风险也随之增大。无论是由于误删除、误格式化、病毒感染还是其他意外情况&#xff0c;数据丢失都可能带来不小的损失。在这种情况下&#xff0c;数据恢复工具应运…

java学习之路-类和对象

前言 本文内容&#xff1a; 类的定义及其使用 this的引用 对象的构造及初始化 封装 static成员 代码块讲解 内部类 文章目录 1.类定义和使用 1.1了解什么是面向对象 1.2简单认识类 1.3定义类 1.4栗子 2.类的使用-类的实例化 2.1什么是实例化 2.2类和对象的说明 3.this引…

基因组de novo组装

分以下几个部分&#xff1a; CLR组装 HIFI组装 ONT组装 二、三代数据矫正 组装结果评估 一、CLR组装 下机数据&#xff1a; 主要用那个bam文件 软件&#xff1a;wtdbg2 第一步&#xff1a;bam转fasta文件 参考&#xff1a;https://www.jianshu.com/p/03c7eb11102d # 进行基…

WEB安全测试通常要考虑的测试点

1、问题&#xff1a;没有被验证的输入 测试方法&#xff1a; 数据类型&#xff08;字符串&#xff0c;整型&#xff0c;实数&#xff0c;等&#xff09; 允许的字符集 最小和最大的长度 是否允许空输入 参数是否是必须的 重复是否允许 数值范围 特定的值&#xff08;枚举型&a…

Node.js介绍

Node.js 是一个开源和跨平台的 JavaScript 运行时环境。它是几乎任何类型的项目的流行工具&#xff01;