java底层原理

2023-05-16

Java运行三部曲:编写,编译,运行
编写:硬件编写代码,就是我们写代码
编译:javac将文件编译成一个或多个.class文件
编译中间的过程主要是类型和格式的检查。
如: Person.java ->词法分析器-〉语法分析器-〉语义分析器-〉字节码生成器
字节码包括class文件相关信息,java源码中的声明和常量信息(元数据),源码中的语句和表头
JVM和Java语言本身没什么关系,JVM只和class文件有关系,其他语言也能具有class文件。
运行:运行字节码文件
加载:将类文件中的字节码加载到JVM内存中
解释执行:逐行执行
类加载器:类加载(类加载)是一种机制,描述的是将字节码以.class文件的形式加载到内存,再经过连接、初始化后,最终形成可以被JVM直接使用的java类型的过程,这个过程只有在运行期才会触发,所以会牺牲一些程序启动的性能,但是却可以提供更高的灵活度。
类加载必经的五个过程:
加载,连接(校验,准备,解析),初始化,使用,卸载。
可以使用-verbose:class方法查看ClassLoader加载过程。
Class是所有类的模板
类是实例的模板
加载loading
概念:加载过程就是将class文件中的字节码‘bytecode’一行一行读入JVM内存中的方法区,但不会执行。
通过类全名来获取定义这个类的二进制字节流,这部分工作由类加载器完成。
将这个字节流所代表的静态存储结构,转化成方法区中运行时数据结构。
在堆中生成一个对应的‘java.lang.Class’对象,作为方法区中这个类的各种数据的访问入口。
JVM在加载数组的时候为了提高效率,减少重复加载(数组中类型统一且固定),加载的是数组的类型,多维数组也是递归加载类型,直到发现非数组类型停止,而数组的创建由JVM直接完成。
提示:基本数据类型和引用数据类型的加载过程没有差别,因为在编译阶段,基本数据类型就会被封装成对应的包装类。
int a ----方法区中 :Integer class
连接linking
概念:连接又分为三个步骤:验证、准备和解析
验证(Verification):检查被加载的类是否有正确的内部结构,包括代码是否正确,类与类之间的关系是否合理等,这与编译时期的检查不同。
准备(Prepanation):为类的静态成员(包括属性和方法)分配内存,并设置初始值(比如null、0、false等).
解析(Resolution):将类的二进制数据中的符号引用(字面量)替换为直接引用(内存地址)。
符号引用(Symbolic References):符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,在class文件中表示我和你的关系,比如全路径名,方法名称等,只要是能无歧义地定位到目标即可。符号引用与JVM内存无关,引用的目标不一定加载到内存中,在Java中,一个类将会编译成一个class文件,在编译时,java类并不知道所引用的类的实际地址,只能用一些符号来替代,各种JVM实现的内存布局可能不一样,但是它们能接受的符号引用是一致的,因为符号引用的字面量明确定义在JVM规范的class文件格式中。
直接引用可以是直接指向目标的指针,比如指向java.lang.Class,指向静态方法,指向静态属性等,还可以是相对偏移量,比如指向属性变量,属性方法等,还可以是一个可以间接定位到目标的句柄。直接引用和JVM布局是相关的,同一个符号引用在不同的VM上翻译出来的直接引用一般会不相同,如果有了直接引用,那引用的目标必定已经被加载到内存中了。总之,直接引用是在JVM中使用内存地址的形式来表示我和你的关系。
例如:
private static String name
属性和局部变量区别?
属性有初始值,不赋值可以使用。
局部变量没有初始值,不赋值不可以使用
在这里插入图片描述
总结:
A.java通过javac编译之后,会形成A.class和B.class(存在于硬件中)
变量b中存的到底是什么?是一个符号“我引用了com.joe.pojo.B类"
类运行时,A和B才被加载到内存中,A分配到内存地址为ex0011,B分配到内存地址为ex0012
B类有了真正的内存地址后,再将之前的符号引用"我引用了com.joe.pojo.B类"转成直接引用ex0012,这个过程就是符号,、引用转成直接引用的过程。
类加载过程
加载:在JVM的方法区中,创建一个对应的instanceKlass区域,然后将class文件中的字节码内容逐行加载对应的instanceKlass中,然后在堆中创建一个对应instanceKlass的Class对象(称为instanceKlass的Java镜像)中。
连接-校验:检查class对象中的代码是否正确。
连接-准备:为类的静态属性和方法分配内存,并设置初始值。
连接-解析:将class对象中的符号引用转成直接引用。
初始化:为类的静态属性赋真正的值,执行静态块。
类加载的触发条件
假设我是一个类,那么:
有人new我的时候,我会被加载,连接,初始化。
有人访问我的静态成员(属性和方法)的时候,我会被加载,连接,初始化。
有人反射,克隆,反序列化我的时候,我会被加载,连接,初始化。
一个类在每次被使用前,都会先检查是否被加载,连接,初始化过:
如果已经被加载,连接,初始化过,则直接使用。
如果仍未被加载,连接,初始化过,则先去执行加载,连接,初始化。
在这里插入图片描述
实例创建方式:
类加载完成之后,才允许根据类来new对应的实例,在new的时候会使用到方法区中对应instanceKlass对象的数据信息。
new的过程就是为实例分配一块连续的堆内存空间过程,方式有两种:
指针碰撞:分配内存空间包括开辟一块新的内存和移动指针两个步骤。
空闲列表:分配内存空间包括开辟一块新的内存和修改空闲列表两个步骤。
-new实例的过程是非原子的,可能会出现并发问题(两个线程争抢到同一块内存),JVM采用CAS乐观锁的方式来解决:
-赵四为某个实例进行new操作,申请到一块内存0x9527,开始操作,查看版本号为000.
-刘能为某个实例进行new操作,申请到同块内存0x9527,开始操作,查看版本号为000.
-赵四操作完成,再次查看版本号,仍为000,提交操作,将版本号更改为001。
-刘能操作完成,再次查看版本号,发现版本号变为了001,放弃这次操作,去申请其他内存。
-最终结果永远不会有两个线程申请到同块内存。
除了CAS乐观锁的方式可以解决并发问题,JVM还提供了一种本地线程额缓冲内存的方式,即每个线程在Java堆中都先提前分配一小块内存区域,称为本地线程分配缓冲T-LAB,各线程给实例分配内存时会在该线程的T-LAB上进行分配,这样各个线程即可互不影响。
扩展——悲观锁:正如其名,具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
实例储存模式:
概念: 在JVMN中,实例在内存中的存储也是很有规律的,存储的布局可以分为三块区域:
(1)对象头区:object Header
存储对象的原数据信息,包括对象运行时数据和类型指针(指向方法区的类型实例)
存储Mark Word,包括对象自身的运行时数据,如它的哈希码和它在GC中分代的年龄、锁状态表示,线程持有锁,偏向锁ID,偏向锁时间戳等信息。
如果是数组对象,还多了一个数组长度。
(2)实例数据区:Instance Data
存储真正有效的数据,即在程序中定义的各种类型的字段数据,这部分数据有一部分是从父类中继承下来的,也有在子类中定义的,总之都要被记录下来。
各字段的分配策略为long/double,int、short/char,byte/boolean,相同宽度的字段总是被分配到一起,便于之后取数据。
(3)对齐填充区:Padding
对齐填充并不一定是必然存在的,因为HotSpot虚拟机内存管理的要求是给实例分配内存的大小必须是8字节的整数倍,所以不够的部分需要填充。又因为对象头部分正好是8字节的倍数,所以对齐填充实际上补全的是实例数据区域,对齐填充的数据并没有特殊的含义,仅仅是起到填充占位符的作用
在这里插入图片描述
实例调用方法
*概念:*在不同的虚拟机中,对象的访问方式也是不同的,主流的访问方式有使用句柄和直接指针两种。
(1)使用句柄:是一种间接使用指针访问实例的方式,因为它需要先在Java堆中划分出一块内存区域作为句柄池。栈中的变量存储的是句柄池中稳定的句柄的地址,而句柄中包含的才是Java堆中的实例和对应的java.lang.Class各自的具体地址。
-使用句柄访问方式的最大好处是栈中的变量存储的是稳定的句柄地址,在实例被移动时只会改变句柄中的类型数据指针,而栈中变量本身不需要被修改。
-直接指针:栈中的变量直接存储的是实例的地址。
-使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的的时间开销。- HotSpot实现中采用的是本方式。
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java底层原理 的相关文章

  • 关于AlreadyExistsError: Another metric with the same name already exists.的解决方案

    这项错误发生在我刚安装完tensorflow xff0c 想import keras包的时候发生了如下的错误 xff1a Tensorflow python framework errors impl AlreadyExistsError
  • uC/OSIII在Cortex-M3的任务切换和中断退出分析

    uC OSIII在任务中执行OSSched相关的函数和在中断退出后都会开始执行调度 xff0c 这是它的调度机制 而按uC OSIII书中所讲 xff0c 普通任务切换和从中断中退出后的任务切换应该是不同的函数 xff0c 因为普通任务切换
  • 每天一个adb命令:dumpsys命令详解

    dumpsys是一个能帮助我们对手机进行性能分析的命令 xff0c 它可以帮助我们获取电池 内存 cpu 磁盘 wifi等等信息 xff0c 具体能查询的信息可以通过命令 xff1a adb span class hljs built in
  • vs2017如何创建一个asax文件

    VS2017无法为网站创建Global asax文件 xff0c 导致出现错误WebForms UnobtrusiveValidationMode 需要 jquery ScriptResourceMapping 解决方案如下 xff1a 勾
  • Spring Security OAuth2.0认证授权

    文章目录 1 基本概念1 1 什么是认证1 2 什么是会话1 3什么是授权1 4授权的数据模型1 4 RBAC1 4 1 基于角色的访问控制 2 基于Session的认证方式3 整合案例3 1 SpringMVC 43 Servlet3 0
  • 浏览器不显示favicon.ico怎么办?

    原因1 xff1a 连接文件的路径不对 如上图路径的话href连接路径应该写成 xff1a href 61 34 img favicon ico 34 xff0c 具体如下 xff1a span class token operator l
  • VNCViewer连接树莓派失败、显示超时的部分原因

    刚入手树莓派 xff0c 在用VNCViewer这款软件实现树莓派的图形化桌面时遇到了一些坑 xff0c 在这里分享 xff0c 希望能对大家有所帮助 1 在文本框内输入IP地址之后一定要记得加上 端号 xff0c 如下图所示 这个端号在P
  • Kubernetes中文手册

    Kubernetes中文手册 https www kubernetes org cn kubernetes pod
  • JSP中文乱码问题终极解决方案

    在介绍方法之前我们首先应该清楚具体的问题有哪些 xff0c 笔者在本博客当中论述的 JSP 中文乱码问题有如下几个方面 xff1a 页面乱码 参数乱码 表单乱码 源文件乱码 下面来逐一解决其中的乱码问题 一 JSP 页面中文乱码 在 JSP
  • JS表白代码

    简单的JS弹窗表白代码 思路 xff1a 只有当用户输入1 xff08 表示喜欢你 xff09 才有进一步浏览的资格 如果用户输入2 xff08 不喜欢你 xff09 就会陷入死循环进行撒娇 xff0c 只有当用户输入1 xff0c 才可以
  • Quartz框架详解

    Quartz框架可以实现 异步定时任务 Quartz框架下载地址 注意1版本和2版本写法完全不一样 xff0c 本文采用的是2 x版本 下载完毕后进入进入lib文件夹 xff0c 然后将下面的几个jar引入项目 xff1a 基本实现步骤 x
  • 前端的端口问题

    本文 xff0c 将以通俗易懂的方式剖析 服务器 电脑 是怎么访问html文件 先说一下前置知识 xff1a 首先我们得知道一件事情 xff1a 电脑中每个运行的程序都对应着某个端口 xff0c 举个例子 xff1a 我们都知道mysql默
  • 湖北师范大学java习题汇编(超详细!已经进行了章节划分)

    表达式和流程控制语句 1 验证歌德巴赫猜想 一个充分大的偶数 xff08 大于或等于6 xff09 可以分解为两个素数之和 试编程序 xff0c 将 6至50之间全部偶数表示为两个素数之和 span class token keyword
  • OPENCV(五) 对给定的车牌进行字符分割

    下面有这样的一个车牌号 xff1a 现在的任务是将每一个字符区分开来 xff0c 并方框圈出来 完成这个功能需要以下的步骤 xff1a 1 灰度处理 span class token comment 读取图片 span image1 spa
  • SpringBoot整合forest(调用彩云API获取所有城市的实时天气)

    Forest简介 xff1a Forest是一个高层的 极简的轻量级HTTP调用API框架 相比于直接使用Httpclient您不再用写一大堆重复的代码了 xff0c 而是像调用本地方法一样去发送HTTP请求 环境配置 xff1a 因为本项
  • JAVA操作Kafka

    一 环境说明 1 电脑或你的服务器需要安装zookeeper和kafka 可以参考我的这篇博客 xff1a 请点击这里 xff01 2 项目中需要下面的依赖 xff1a span class token tag span class tok
  • Gradle使用本地maven仓库

    一 基本配置 在repositories下添加mavenLocal 方法 plugins span class token punctuation span id span class token string 39 java 39 spa
  • Docker容器编排

    一 简介和下载安装 1 简介 docker compose是Docker官方的开源项目 xff0c 可以管理多个docker容器组成的一个应用 你需要定义一个YAML格式的配置文件docker compose yaml xff0c 写好多容
  • 若依微服务(ruoyi-cloud)保姆版容器编排运行

    一 简介 项目gitee地址 xff1a https gitee com y project RuoYi Cloud 由于该项目运行有很多坑 xff0c 大家可以在git克隆拷贝到本地后 xff0c 执行下面的命令使master版本回退到本
  • 深入学习Tomcat----自己动手写服务器(附服务器源码)

    相信大多 Web 开发者对 Tomcat 是非常熟悉的 xff0c 众所周知 Tomcat 是一款非常好用的开源 Servlet 容器 xff0c 您一定对这个最流行的 Servlet 容器充满好奇 xff0c 虽然它并不像一个黑盒子那样让

随机推荐

  • Docker图形界面

    一 Portainer Portainer是一款轻量级的应用 xff0c 它提供了图形化界面 xff0c 用于方便地管理Docker环境 xff0c 包括单机环境和集群环境 官网 xff1a https www portainer io 运
  • Docker网络

    一 简介 从其架构和运行流程来看 xff0c Docker是一个C S模式的架构 xff0c 后端是一个松耦合架构 xff0c 众多模块各司其职 docker运行的基本流程为 xff1a 1 用户是使用Docker Client和Docke
  • NOKOV Seeker2.2动作捕捉软件与ROS的通信

    一 动捕软件安装与数据准备 1 在操作系统为Windows系统 xff0c 且位数为64位的电脑上 xff0c 以鼠标右键点击 以管理员身份运行 的方式 xff0c 运行 Seeker2 2 Tracker setup exe 文件 xff
  • NOKOV度量动捕软件教程(1):软件安装与设置

    一 软件安装 1 在操作系统为 64 位的 Windows 系统上 xff0c 关闭防火墙退出杀毒软件 xff08 360 电脑管家等 xff09 xff0c 以鼠标右键点击 以管理员身份运行 的方式 xff0c 运行 XINGYING 1
  • Pixhawk+PX4+NOKOV+C++SDK动捕飞控方案

    一 PX4配置 1 参数设置 xff0c 保存重启后生效 EKF2 AID MASK 61 24 EKF2 HGT MODE 61 2 二 动捕软件设置 1 配置参考 xff08 1 xff09 mocap nokov ROS Wiki 三
  • Pixhawk+PX4+NOKOV+VRPN动捕飞控方案

    一 PX4 配置 1 参数设置 xff0c 保存重启后生效 EKF2 AID MASK 61 24 EKF2 HGT MODE 61 2 二 VRPN配置 1 Nokov 动捕软件正确配置参数并启动 VRPN 2 使用 vrpn clien
  • JS-DOM— —节点操作

    五 节点操作 5 1 节点操作的作用 获取元素通常使用两种方式 1 利用DOM提供的方法获取元素 document getElementByld document getElementsByTagName0 document querySe
  • 立创EDA专业版入门经验分享(1)——对标AD的快捷操作

    作者团队在近期从Alitum Designer转战到立创EDA专业版 在习惯AD的工作方式后 xff0c 转到立创EDA专业版后磨合了很长一段时间 现将原来AD中的功能对应到立创EDA中的高级功能像大家分享 欢迎大家一起交流学习 本帖将作为
  • c语言中字符数组的理解

    数组的理解参考该文 对于字符数组 xff0c 当最后一个元素是 0 xff0c 则这个字符数组是一个字符串 xff1b 字符串可以通过首地址来打印输出 1 对于一维数组 int pack 3 61 1 2 3 printf 34 d 34
  • 如何减小与“大牛”的差距

    为什么同样的时间有的人可以漂亮的完成工作 xff0c 而有些人废了很大的力气也没有完成 xff1f 前者我们常常称之为 大牛 xff0c 后者我们常常叫他们 菜鸟 当然 大牛 都是相对而言的 xff0c 大牛 也不可能方方面面都非常厉害 x
  • 利用字符串的最后一个字符为‘\0‘的特性操作字符串

    利用末尾为 0 特性 xff0c 求字符串长度 xff0c 实现strlen int len 61 0 char str 61 34 hello 34 char p 61 str while p len 43 43 计算字符串的长度 p 4
  • 信号量sem_init,sem_wait,sem_post

    本篇文章是信号量的简单入门 xff0c 主要学习关于信号量四个函数的使用 文章综合整理了两篇文章 xff1a http blog csdn net qyz og article details 47189219 http blog csdn
  • readdir函数

    readdir会不断读取目中的文件及目录 xff0c 但不会读子目录中的文件 include lt sys types h gt include lt dirent h gt include lt stdio h gt include lt
  • fwrite写文件是乱码

    fwrite写的二进制文件 xff0c 所以我们打开所写的文件是乱码 xff0c 但数据是正确的 xff0c 我们通过fread函数按照原来的数据格式读取即可 可以参考该文 include lt sys types h gt include
  • 经典面试题 动态链接库与静态链接库的区别

    经典面试题 动态链接库与静态链接库的区别 面试轻松学习 xff0c offer快点拿 文章目录 经典面试题 动态链接库与静态链接库的区别一 动态链接库是什么 xff1f 二 静态链接库是什么 xff1f 三 区别1 静态链接库速度快 xff
  • Docker占用的磁盘空间清理

    Docker占用的磁盘空间清理 1 docker system命令 在谁用光了磁盘 xff1f Docker System命令详解中 xff0c 我们详细介绍了docker system命令 它可以用于管理磁盘空间 docker syste
  • 卡尔曼滤波算法详细推导(全网最详细的推导过程)

    本文是来源于B站Dr CAN的视频的学习笔记 xff0c 有需要详细了解的 xff0c 可以到B站看相关视频DR CAN的个人空间 1 递归算法 例 xff1a 假设测一段距离 xff0c 第一次测 z 1 z 1 z 1 61 50 1m
  • ADC采样滤波算法利用卡尔曼滤波算法详解

    1 ADC采样模型 xff08 本文为笔者早期所写 xff0c 当时对卡尔曼滤波器理解尚未透彻 xff0c 如今回顾 xff0c 该模型还有所缺陷 xff0c 推荐读者看卡尔曼的推导过程或者B站大佬Dr CAN的空间 xff09 假设ADC
  • 微信支付趟过的坑

    这段时间在做微信支付开发 xff0c 在公司的公众号审批下来后 xff0c 我这边的测试用例也已经开发完毕 xff0c 于是拿着具体的数据来调试了 xff0c 大段大段的代码就不贴了 xff0c demo里有 xff0c 这里就说说调试过程
  • java底层原理

    Java运行三部曲 xff1a 编写 xff0c 编译 xff0c 运行 编写 xff1a 硬件编写代码 xff0c 就是我们写代码 编译 xff1a javac将文件编译成一个或多个 class文件 编译中间的过程主要是类型和格式的检查