当前位置: 首页 > article >正文

【Java-JVM】

在学习JVM之前,先了解Java程序执行过程和Java为什么跨平台,有助于我们对JVM的理解。

Java的执行过程:

        1. 编译 通过Java命令,调用JDK编译器将*.java源文件编译成*.class字节码文件。

        2. 执行 通过java命令,调用JVM虚拟机,执行*.class字节码文件。

Java程序的跨平台原因:

        1. 通用字节码文件 JDK编译器在不同平台编译相同源文件的字节码文件都是相同的。

        2. 不同版本JVM虚拟机 不同平台执行字节码文件会用到不同的JVM虚拟机,将字节码翻译成当前平台可以执行的机器码指令。

JDK、JRE、JVM:

        JDK:Java开发工具包,提供javac编译器、jheap、jconsole等监控工具。

        JRE:Java运行环境,提供Class Library 核心类库+JVM。

        JVM:Java虚拟机,用于运行Java应用程序。

JVM的组成结构:

        JVM由JVM解释器、JIT解释编译器、类加载器、运行时数据区、垃圾回收器、本地方法库等部分组成。

1. JVM的执行方式

        JVM以解释+编译混合模式,执行字节码文件。

        解释执行为主,执行过程中,JVM将每个字节码文件中的每个指令,通过解释器转换成当前平台可以识别的机器码,然后交给CPU执行。
        为了提高执行效率,JVM还会在运行期间,JVM通过热点代码的统计分析,识别高频的方法调用,循环体、公共模块等,当超过阈值时,JVM会基于JIT即时编译器(just-in-time compiler )将热点代码转换成机器码,直接交给CPU 执行,提高执行效率。

2. JVM类加载机制

        程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载、连接、初始化3个步骤来对该类进行初始化。如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化。

2.1 类加载过程包含加载、验证、准备、解析和初始化。

1. 加载

        这里的「加载」是「类加载」过程的一个阶段,「类加载」描述的是整个过程,「加载」仅表示「类加载」的第一阶段。

        在加载阶段,JVM主要完成以下3件事:

                1.通过类的完全限定名称获取定义该类的*.class 字节码文件的二进制字节流。
                2.将该字节流表示的静态存储结构转换为Metaspace元空间区的运行时存储结构。
                3.在内存中生成一个代表该类的Class对象,作为元空间区中该类各种数据的访问入口。

2. 验证

        验证是为了确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。如果验证到输入的字节流不符合 Class 文件格式的约束,虚拟机就会抛出一个 java.lang.VerifyError 异常或其子类异常。
验证阶段大致完成 4 个阶段的检验动作:

        文件格式验证

        元数据验证

        字节码验证

        符号引用验证

3. 准备

        准备阶段是正式为类变量(static 修饰的变量)分配内存并设置类变量初始值的极端,这些变量所使用的内存都将在方法区中进行分配。注意此时进行内存分配的仅包括类变量,而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在 Java 堆中。 

4. 解析

         解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程

        符号引用:只包含语义信息,不涉及具体实现,以一组符号来描述引用目标,是字面量;符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。

        直接引用:与具体实现息息相关,是直接指向目标的指针;直接引用是可以直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。如果有了直接引用,那引用的目标必定已经在内存中存在。

5. 初始化

        初始化阶段,才真正开始执行类中定义的 Java 程序代码(或者说是字节码) 

        在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量和其他资源。

        也就是我们通常理解的赋初始值以及执行静态代码块。

2.2 类加载器

        在类加载过程的加载阶段,通过类的完全限定名,获取描述类的二进制流的实现类,被称为“类加载器”。
        从JVM虚拟机的角度来讲,只存在以下两种不同的类加载器:

                1.启动类加载器(Bootstrap ClassLoader ),使用C++实现,是虚拟机的一部分;
                2.其它类的加载器,使用Java实现,独立于虚拟机,继承自抽象类java.lang.classLoader。

        从Java开发人员的角度可以分为: 

                1.启动类加载器(Bootstrap ClassLoader):负责将存放在 <JAVA_HOME>\lib 目录中的,或者被 -Xbootclasspath 参数所指定的路径中的,并且是虚拟机识别的(仅按文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录中也不会被加载)类库加载到虚拟机内存中。
                2.扩展类加载器(Extension ClassLoader):负责加载 <JAVA_HOME>\lib\ext 目录中的,或者被 java.ext.dirs 系统变量所指定的路径中的所有类库。
                3.应用程序类加载器(Application ClassLoader):也称为系统类加载器,负责加载用户类路径(ClassPath)上所指定的类库。如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

3. 运行时数据区

        JVM虚拟机在执行Java程序的过程中会把它管理的内存划分成若干个不同的数据区域。由方法区、堆区、虚拟机栈、本地方法栈、程序计数器务部分。

        JDK 1.8之前分为:线程共享(Heap堆区、Method Area方法区),线程私有(虚拟机栈、本地方法栈、程序计数器)

      JDK 1.8之后分为:线程共享(Heap 堆区、MetaSpace 元空间),线程私有(虚拟机栈、本地方法栈、程序计数器)

4. JVM垃圾收集器 

分类:

1.按照执行原理分类:
单线程收集器:
        Serial垃圾收集器

        Serial Old垃圾收集器

多线程收集器:
        ParNew垃圾收集器

        Parallel Scavenge垃圾收集器

        Parallerl Old垃圾收集器

并发收集器:
        CMS收集器

        G1收集器
2.按照作用区域分类:
新生代:
           Serial垃圾收集器

           Parallel Scavenge垃圾收集器

           ParNew垃圾收集器

老年代:
        Serial Old垃圾收集器

        Parallerl Old垃圾收集器

        CMS收集器

整个Java堆:
        G1收集器

具体介绍: 

1.Serial垃圾收集器
定义:用于新生代,是单线程收集器,使用复制算法
缺点:单线程完成垃圾回收,在进行垃圾回收时,必须暂停其他所有工作线程,直到垃圾收集结束

2.Serial Old垃圾收集器
定义:用于老年代,是单线程收集器,使用标记整理算法
用途:jdk5.0之前版本与新生代Parallerl Scavenge收集器搭配使用
          在老年代中作为CMS收集器的后备垃圾收集方案

3.ParNew垃圾收集器
定义:多线程收集器,使用复制算法,是JVM在Server模式下新生代的默认垃圾回收器
缺点:和Serial一样,多线程进行垃圾回收时也要暂停其他所有工作线程

4.Parallerl Scavenge收集器
定义:多线程垃圾收集器,使用复制算法,用于新生代中
优点:使得程序达到一个可控的吞吐量,高吞吐量能够最高效率利用CPU时间;采用自适应调节策略

5.Parallel Old收集器
定义:用于老年代,使用标记整理算法,是多线程垃圾收集器
用处:能够在老年代提供吞吐量优先的垃圾收集器

6.CMS收集器
定义:CMS(Concurrent mark sweep),用于老年代的多线程垃圾收集器,使用标记清除算法,属于并发执行的垃圾收集器
作用:获取最短垃圾回收停顿时间,从而提高用户体验

过程:
        初始标记:标记GC Roots能直接管理的对象,需要暂停所有工作线程
        并发标记:进行GC Roots跟踪,和用户线程一起工作,无需暂停工作线程
        重新标记:修正在并发标记期间,因用户程序工作导致标记变动的标记记录
        并发清除:清楚GC Roots不可达对象,无需暂停工作线程

7.G1收集器
定义:G1(Garbage First)使用标记整理算法
优点:不会产生内存碎片
           可以精确控制停顿时间,实现低停顿的垃圾回收
           将整个Java堆内存划分为几个固定区域,优先回收垃圾最多的区域


http://www.kler.cn/news/324505.html

相关文章:

  • Vue之axios请求
  • 性能优化-数据库索引优化实战指南
  • 【Flume Kafaka实战】Using Kafka with Flume
  • ISA Server配置https踩坑全过程
  • 【初阶数据结构】排序——插入排序
  • Vue.js与Flask/Django全栈开发实战:从零搭建前后端分离的高效Web应用,打造现代化全栈开发体验!
  • HAL库I2C通用驱动程序(HAL I2C Generic Driver)
  • 英伟达Blackwell系列显卡揭秘:RTX 5090与RTX 5080引领性能新高度
  • [SAP ABAP] SELECTION-SCREEN
  • LeetCode - #124 二叉树中的最大路径和(Top 100)
  • 如何使用tcpdump android手机抓包
  • AI大模型的基本流程
  • 2025第四届深圳国际数据中心液冷散热展会
  • Certbot自动申请并续期https证书
  • 01_OpenCV图片读取与展示
  • numpy数组与矩阵运算
  • 自动化运维的利器:Ansible、Puppet和Chef详解
  • OpenAPI鉴权(二)jwt鉴权
  • 关于 SQL 的 JOIN 操作
  • 【接口测试】测试试题
  • 工作中使用人工智能的政策和程序的重要性
  • 【YOLO目标检测反光衣数据集】共2388张、已标注txt格式、有训练好的yolov5的模型
  • 服务器感染了.lcrypt勒索病毒,如何确保数据文件完整恢复?
  • 【VUE】vue-router
  • [uni-app]小兔鲜-04推荐+分类+详情
  • CSS 中的overscroll-behavior属性
  • 国产化低功耗低延时广覆盖物联网无线通讯方案_LAKI芯片
  • [数据集][目标检测]辣椒缺陷检测数据集VOC+YOLO格式695张5类别
  • C/C++语言基础--C++面向对象、类、对象概念讲解
  • Qt开发技巧(九)去掉切换按钮,直接传样式文件,字体设置,QImage超强,巧用Qt的全局对象,信号槽断连,低量数据就用sqlite