【JVM】JVM的组成与执行流程

news2024/9/24 13:21:38

JVM 由哪些部分组成,运行流程是什么?

JVM 是什么

Java Virtual Machine Java程序的运行环境(java二进制字节码的运行环境)

好处:

  • 一次编写,到处运行
  • 自动内存管理,垃圾回收机制

JVM的组成

我们首先看一下一个程序的完整执行流程:

 所以可以看出JVM主要是由四部分组成:

  • ClassLoader(类加载器)
  • Runtime Data Area(运行时数据区,内存分区)
  • Execution Engine(执行引擎)
  • Native Method Library(本地库接口)

JVM运行流程

由此我们说一下JVM的大体的运行流程:

  1. 类加载器(ClassLoader)把Java代码转换为字节码
  2. 运行时数据区(Runtime Data Area)把字节码加载到内存中,而字节码文件只是JVM的一套指令集规范,并不能直接交给底层系统去执行,而是有执行能力的执行引擎运行
  3. 执行引擎(Execution Engine)将字节码翻译为底层系统指令,再交由CPU 执行去执行,此时需要调用其他语言的本地库接口(Native Method Library)来 实现整个程序的功能。

其中在运行时数据区中有很多组件组成,这个也是JVM的重中之重

运行数据区的组成

运行时数据区主要是由以下几部分组成:

  • 程序计数器
  • 虚拟机栈
  • 本地方法栈
  • 方法区/元空间

下面来介绍一下程序计数器

程序计数器

在Java中,任务的执行时多线程并发执行的,但是这个并发指的是多个线程交替执行。在任何的一个时间点上,一个处理器只会执行一个线程,如果当前线程它所分配的执行时间用完了,就会被‘挂起’。处理器会切换到另外一个线程上来进行执行并且这个线程执行时间用完了,接着处理器就会用来执行被挂起的线程

那么问题就会出现了,当前处理器如何知道上一次线程执行到什么位置呢?程序计数器,可以解决这个问题,程序计数器会回到当前这个线程上一次执行的行号,案后继续向下执行

程序计数器:线程私有的,内部保存的字节码的行号。用于记录正在执行的字节码指令的地址

javap -verbose  xx.class    打印堆栈大小,局部变量的数量和方法的参数

程序计数器是JVM规范中唯一一个没有规定出现OOM的区域,所以这个空间也不会进行GC

线程共享的区域:主要是用来保存对象实例、数组等,党对中没有内存空间可以分配给实例,也无法再扩展时就会抛出OOM(OutOfMemoryError)异常

其中堆主要是分为两个部分:年轻代、老年代和永久代(Java8将其移动到本地内存中)

  • 年轻代:年轻代主要是被划分为三部分,Eden区和两个大小严格相同的Survivor区,根据JVM的策略,在经过几次垃圾收集后,让人然存活在Survivor会移动到老年代
  • 老年代:老年代主要是保存生命周期比较长的对象
  • 永久代:永久代保存的时类信息、静态变量、常量、编译后的代码

永久代的大小是固定的,并且在运行时不容易进行调整。这意味着如果应用加载的类过多,或者类的信息占用空间过大,很容易就会填满永久代的固定空间,从而引发 OOM 错误,而在 Java 8 中,将永久代移动到本地内存并重新开辟为元空间,在一定程度上缓解了 OOM 问题。这是因为元空间的使用不再受限于 JVM 堆的大小。元空间使用的是本地内存,其空间相对较大,并且可以根据实际需要动态扩展

 虚拟机栈和本地方法栈

Java Virtual machine Stacks (java 虚拟机栈)

  • 每个线程运行时所需要的内存,称为虚拟机栈,先进后出
  • 每个栈由多个栈帧(frame)组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

栈解决的是程序运行的问题,栈里面存的是栈帧,栈帧里面存的是局部变量 表、操作数栈、动态链接、方法出口等信息

本地方法栈与栈功能相同,本地方法栈执行的是本地方法,一个Java调用非 Java代码的接口。

 垃圾回收是否涉及栈内存?

垃圾回收主要指就是堆内存,当栈帧弹栈以后,内存就会释放

栈内存分配越大越好吗?

未必,默认的栈内存通常为1024k 栈帧过大会导致线程数变少,例如,机器总内存为512m,目前能活动的线程 数则为512个,如果把栈内存改为2048k,那么能活动的栈帧就会减半

方法内的局部变量是否线程安全?

如果方法内局部变量没有逃离方法的作用范围,它是线程安全的

如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全

栈内存溢出情况:栈帧过多导致栈内存溢出,典型问题:递归调用 

元空间

元空间是各个线程共享的内存区域,主要是存储类的信息、运行时常量池。在虚拟机启动时创建,关闭时销毁。如果方法区域中的内存无法满足分配请求,则会抛出OOM

常量池可以看成一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型等信息 

查看字节码结构(类的基本信息、常量池、方法定义) javap -v xx.class

比如下面是一个Application类的main方法执行,源码如下:

public class Application {
    public static void main(String[] args) {
         System.out.println("hello world");
    }
}

 找到类对应的class文件存放目录,执行命令: javap -v Application.class 查看字节码结构

D:\code\jvm-demo\target\classes\com\heima\jvm>javap -v 
Application.class
 Classfile /D:/code/jvm
demo/target/classes/com/heima/jvm/Application.class
 Last modified 2023-05-07; size 564 bytes    
//最后修改的时间
MD5 checksum c1b64ed6491b9a16c2baab5061c64f88   //签名
Compiled from "Application.java"   //从哪个源码编译
public class com.heima.jvm.Application   //包名,类名
minor version: 0
 major version: 52     
//jdk版本
flags: ACC_PUBLIC, ACC_SUPER  //修饰符
Constant pool:   //常量池
#1 = Methodref          
#6.#20         
<init>":()V
 #2 = Fieldref           
#21.#22        
// java/lang/Object."
 // 
java/lang/System.out:Ljava/io/PrintStream;
 #3 = String             
#23            
#4 = Methodref          
#24.#25        
// hello world
 // 
java/io/PrintStream.println:(Ljava/lang/String;)V
 #5 = Class              
#26            
com/heima/jvm/Application
 #6 = Class              
#7 = Utf8               
#8 = Utf8               
#9 = Utf8               
#10 = Utf8               
#11 = Utf8               
#27            
<init>
 ()V
 Code
 LineNumberTable
 // 
// java/lang/Object
 LocalVariableTable
 #12 = Utf8               
#13 = Utf8               
#14 = Utf8               
#15 = Utf8               
#16 = Utf8               
#17 = Utf8               
#18 = Utf8               
#19 = Utf8               
#20 = NameAndType        
#21 = Class              
#22 = NameAndType        
out:Ljava/io/PrintStream;
 #23 = Utf8               
#24 = Class              
#25 = NameAndType        
(Ljava/lang/String;)V
 #26 = Utf8               
#27 = Utf8               
#28 = Utf8               
#29 = Utf8               
this
 Lcom/heima/jvm/Application;
 main
 ([Ljava/lang/String;)V
 args
 [Ljava/lang/String;
 SourceFile
 Application.java
 #7:#8          
#28            
#29:#30        
hello world
 #31            
#32:#33        
// "<init>":()V
 // java/lang/System
 // 
// java/io/PrintStream
 // println:
 com/heima/jvm/Application
 java/lang/Object
 java/lang/System
 out
下图,左侧是main方法的指令信息,右侧constant pool  是常量池
  #30 = Utf8               Ljava/io/PrintStream;
  #31 = Utf8               java/io/PrintStream
  #32 = Utf8               println
  #33 = Utf8               (Ljava/lang/String;)V
 {
  public com.heima.jvm.Application();  //构造方法
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method 
java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/heima/jvm/Application;
  public static void main(java.lang.String[]);  //main方法
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field 
java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String hello world
         5: invokevirtual #4                  // Method 
java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 7: 0
        line 8: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
 }
 SourceFile: "Application.java"

 下图,左侧是main方法的指令信息,右侧constant pool 是常量池 main方法按照指令执行的时候,需要到常量池中查表翻译找到具体的类和方法地址去执行

运行时常量池:常量池是 *.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

redis集群 高可用

目录 主从复制 主从复制的流程 部署主从复制 步骤 哨兵模式 数据流向 步骤 故障恢复 cluster集群 数据流向 步骤 redis集群的三种模式&#xff1a; 主从复制 奇数台 1主2从 哨兵模式 奇数台 1主2从 cluster 集群 6 台 主从复制 原理&#xff1a;主可以…

(四)延时任务篇——redisson实现延迟任务实战

前言 上一节内容中介绍了如何使用redis的zset结构实现延迟任务的实战内容&#xff0c;从使用角度来说还是略显繁琐&#xff0c;而且定时任务的方式扫描redis获取过去的任务也会存在任务空转的问题。在此基础上&#xff0c;我们可以使用redisson的阻塞队列&#xff0c;完成延迟…

探索 Python 的新世界:funcy 库的神奇之旅

文章目录 探索 Python 的新世界&#xff1a;funcy 库的神奇之旅背景&#xff1a;为何 funcy 如此迷人&#xff1f;简介&#xff1a;funcy 库是什么&#xff1f;安装&#xff1a;如何将 funcy 纳入你的项目&#xff1f;功能&#xff1a;funcy 的五大法宝应用&#xff1a;funcy 在…

图方法与机器学习实战:从理论到应用的全景指南

《动手学图机器学习》并不是一本纯粹介绍图机器学习理论的著作&#xff0c;Alessandro Negro 博士作为科学家和 Reco4 公司的 CEO&#xff0c;长期维护图数据源的推荐系统。他结合机器学习工程和图机器学习方法&#xff0c;通过推荐引擎、欺诈检测和知识图谱等案例&#xff0c;…

一键式RWKV RAG、RWKV-Keras、新论文...RWKV社区7月动态速览!

大家好&#xff0c;《RWKV 社区最新动态》迎来了第三期内容&#xff0c;本期统计了 RWKV 社区 7 月的重要动态&#xff0c;一起来看看吧&#xff01; 省流版本&#xff1a; RWKV 官方公告 RWKV-6-World 14B 模型已发布RWKV 中文官网 rwkv.cn 正式上线 RWKV 社区新项目 RWKV R…

LeetCode删除链表的倒数第 N 个结点

给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例 3&#x…

C++进阶(12)智能指针

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;C 一、概述 智能指针在构造的时候开辟空间&#xff0c;当智能指针生命周期结束则会自动调用析构函数释放空间。 解决问题&#xff1a;对于new开辟的时候出现异常&#xff0c;导致之前开辟的空间没有手动释放…

VMware虚拟机安装Windows7教程(超详细)

目录 1. 下载2. 安装 VMware3. 安装 Window73.1 新建虚拟机3.2 安装操作系统 4. 设置共享文件夹5. 安装 VMware Tools5.1 下载&安装缺少驱动5.2 开始安装 VMware Tools 6. 未&#x1f414;&#x1f525;解决 创作不易&#xff0c;禁止转载抄袭&#xff01;&#xff01;&…

MyBatis代码生成器:SpringBoot 引入MybatisGenerator

1. 引入插件 <plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.5</version><configuration><!--generator配置⽂件所在位置--><configurati…

7.5 grafana上导入模板看图并讲解告警

本节重点介绍 : blackbox_exporter grafana大盘导入和查看告警配置讲解 grafana大盘 grafana 上导入 blackbox_exporter dashboard 地址 https://grafana.com/grafana/dashboards/13659举例图片http总览图value_mapping设置 展示设置阈值&#xff0c;展示不同背景色 告警配…

过滤和筛选树形结构数据

场景 在平时项目开发中经常会遇到树形数据的处理&#xff0c;如树形数据根据条件值过滤掉不符合条件的选项&#xff0c;如果是最后的子数据符合条件那么就会保存这条树形链路的所有直属数据并过滤掉所有非直属的数据。如果是符合条件的数据还有子元素&#xff0c;那么就保留所…

算法强训day18

一、压缩字符串 链接&#xff1a;压缩字符串(一)_牛客题霸_牛客网 #include<iostream> using namespace std; #include<vector> class Solution { public:/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可***…

mac电脑不能快速传输文件的原因是什么 mac无法拷贝文件到移动硬盘的原因是什么 macbook传输速度慢

新买的移动硬盘连接上Mac电脑&#xff0c;想要将Mac上的文件拷贝到移动硬盘里&#xff0c;但是Mac无法拷贝文件到移动硬盘里&#xff0c;直接拖拽、剪切都不行&#xff0c;尤其是一些大的安装包或视频文件的拷贝&#xff0c;需要花费大量的时间&#xff0c;给Mac用户造成了很多…

Excel文档受损打不开,还能修复吗?

Excel作为最常用的表格文件&#xff0c;在我们日常的工作当中使用尤其频繁&#xff0c;且经常涉及到一些重要数据文件的编辑和保存。然而&#xff0c;有时我们会遇到Excel文档受损而无法打开的情况&#xff0c;这无疑会给我们的工作带来诸多不便。那么&#xff0c;当Excel文档受…

SpringCloud API网关

SpringCloud API网关 文章目录 SpringCloud API网关1. 概念2. Spring Cloud Gateway2.1 介绍2.2 操作方式 3.Route Predicate Factories3.1 介绍3.2 使用方式 1. 概念 API网关&#xff0c;简称网关&#xff0c;本身是一个服务&#xff0c;通常作为后端服务的唯一入口&#xff…

git学习准备阶段

准备阶段 ubantu下载安装git sudo apt-get install git查看git版本 git -v注册用户名 git config --global user.name [name][name]填入自己的名字&#xff0c;如果没有空格的情况下&#xff0c;可以不加引号,–global是在全局下操作&#xff0c;如果没有这个参数就只是在本…

Orcale(备份导入导出)

1.备份恢复 1.1.备份定义 备份就是把数据库复制到转储设备的过程。其中&#xff0c;转储设备是指用于放置数据库副本的磁带或磁盘。通常也将存放于转储设备中的数据库的副本称为原数据库的备份或转储。备份是一份数据副本 1.2.备份分类 从物理与逻辑的角度来分类&#xff1a…

C++ 哈希系列容器 + 位图 + 布隆过滤器

目录 1 unordered 系列关联式容器 2 哈希介绍 3 闭散列哈希 4 哈希桶 5 封装实现unordered系列set和map 6 位图 7 哈希切割 8 布隆过滤器 1 unordered 系列关联式容器 在学习哈希结构实现之前&#xff0c;我们先学习一下哈希在库里面的一些使用unordered_set 和unorderen_m…

昂科烧录器支持HolyChip芯圣电子的8位触摸微控制器HC88T3661

芯片烧录行业领导者-昂科技术近日发布最新的烧录软件更新及新增支持的芯片型号列表&#xff0c;其中HolyChip芯圣电子的8位触摸微控制器HC88T3661已经被昂科的通用烧录平台AP8000所支持。 HC88T3661是一颗采用高速低功耗CMOS工艺设计开发的增强型8位触摸微控制器&#xff0c;内…

探索全光网技术 | 全光网络技术方案选型建议一 (办公室场景)

全光网技术方案选型建议 | 办公室场景 目录 一、场景设计需求二、办公室场景拓扑三、部署方式四、产品相关规格说明五、方案优势与特点 校园办公室网络是校园员工日常处理工作的重要载体&#xff0c;学校领导、教学、研究、行政、财务等各部门均需要办公室网络来承载日常的工作…