JVM类加载与运行时数据区

目录

一、类加载器

jvm类的加载过程

第一阶段:加载

第二阶段:链接阶段

第三阶段:初始化阶段:

双亲委派机制

沙箱安全机制

运行时数据区

栈-Xss1m

TLAB

逃逸分析

方法区

常量池中有什么

StringTable为什么要调整位置

静态变量存放在那里?

对象实例化内存布局与访问定位

运行时元数据

类型指针

实例数据(Instance Data)

对齐填充说明

StringTable

注意

字符串拼接操作


一、类加载器

jvm类的加载过程

第一阶段:加载

通过一个类的全限定名获取定义此类的二进制字节流

将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

第二阶段:链接阶段

验证 :文件格式 元数据验证 字节码验证 符号引用验证

准备:为类变量分配内存 设置默认值

解析: 符号引用转换为直接引用

事实上,解析操作往往会伴随着JVM在执行完初始化之后再执行。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等。对应常量池中的CONSTANT Class info、CONSTANT Fieldref info、CONSTANT Methodref info等

第三阶段:初始化阶段:

为静态变量赋予正确的初始值

执行类构造器 虚拟机必须保证一个类的<clinit>()方法在多线程下被同步加锁。 从上面可以看出初始化后,只能够执行一次初始化,这也就是同步加锁的过程

双亲委派机制

方法 getParent()

loadClass() 双委派机制

findClass() 编写加载规则 将取得的字节码转换成流

defineClass() 生成类的class对象

  protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// 首先,检查类是否已经加载Class<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {if (parent != null) {//类加载器有父类加载器,使用父类加载器加载c = parent.loadClass(name, false);} else {//直到顶级类加载器,即parent为空时,由findBootstrapClassOrNull()方法尝试到Bootstrap ClassLoader中检查目标类。c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// ClassNotFoundException thrown if class not found// from the non-null parent class loader}if (c == null) {// 如果仍未找到,则调用findClass来查找该类。long t1 = System.nanoTime();//通过findClass()方法尝试到对应的类目录下去加载目标类。c = findClass(name);// this is the defining class loader; record the statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {//如果加载成功,则根据resolve参数决定是否要执行连接过程,并返回Class对象。resolveClass(c);}return c;}}

Service Provider Interface,SPI)的代码,现在问题来了,启动类加载器是绝不可能认识、加载这些代码的,那该怎么办?(SPI:在Java平台中,通常把核心类rt.jar中提供外部服务、可由应用层自行实现的接口称为SPI)

为了解决这个困境,Java的设计团队只好引入了一个不太优雅的设计:线程上下文类加载器(Thread Context ClassLoaden),这个类加载器可以通过java.lang.Thread类的setContextClassLoader()方法进行设置,如果创建线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认就是应用程序类加载器。

JNDI服务使用这个线程上下文类加载器去加载所需的SPI服务代码,这是一种父类加载器去请求子类加载器完成类加载的行为,这种行为实际上是打通了双亲委派模型的层次结构来逆向使用类加载器,已经违背了双亲委派模型的一般性原则。在JDK 6时,DK提供了java.util.ServiceLoader类,以META-INF/services中的配置信息,辅以责任链模式,这才算是给SPI的加载提供了一种相对合理的解决方案。

Java虚拟机对class文件采用的是按需加载的方式

  • 避免类的重复加载

  • 保护程序安全,防止核心API被随意篡改

沙箱安全机制

沙箱机制就是将Java代码限定在虚拟机(VN)特定的运行范围中,并且严格限刺代码对本地系统资源访问。通过这样的措施来保证对代码的有限隔离,防止对本地系统造成破坏。

运行时数据区

栈-Xss1m

  • 局部变量表(Local Variables)

  • 操作数栈(operand Stack)(或表达式栈)

  • 动态链接(DynamicLinking)(或指向运行时常量池的方法引用)

  • 方法返回地址(Return Address)(或方法正常退出或者异常退出的定义)

每一个栈帧内部都包含一个指向运行时常量池该栈帧所属方法的引用。包含这个引用的目的就是为了支持当前方法的代码能够实现动态链接(Dynamic Linking)。比如:invokedynamic指令

比如:描述一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的,那么动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用。

堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。

所有的对象实例以及数组都应当在运行时分配在堆上。

  • “-Xms"用于表示堆区的起始内存,等价于-xx:InitialHeapSize

  • “-Xmx"则用于表示堆区的最大内存,等价于-XX:MaxHeapSize

通常会将-Xms和-Xmx两个参数配置相同的值,其目的是为了能够在ava垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小,从而提高性能

  • Eden:From:to -> 8:1:1

  • 新生代:老年代 - > 1 : 2

几乎所有的Java对象都是在Eden区被new出来的。绝大部分的Java对象的销毁都在新生代进行了。(有些大的对象在Eden区无法存储时候,将直接进入老年代)

YGC次数达到15次还存活的对象,会移动到老年代。次数可以设置。默认是15次。

  • 针对幸存者s0,s1区的总结:复制之后有交换,谁空谁是to

  • 关于垃圾回收:频繁在新生区收集,很少在老年代收集,几乎不再永久代和元空间进行收集

  • 新生代采用复制算法的目的:是为了减少内碎片

部分收集:不是完整收集整个Java堆的垃圾收集。其中又分为:

  • 新生代收集(MinorGC/YoungGC):只是新生代(Eden\s0,s1)的垃圾收集

  • 老年代收集(MajorGC/o1dGC):只是老年代的圾收集。

TLAB

VM为每个线程分配了一个私有缓存区域,它包含在Eden空间内。

多线程同时分配内存时,使用TLAB可以避免一系列的非线程安全问题,同时还能够提升内存分配的吞吐量,因此我们可以将这种内存分配方式称之为快速分配策略

逃逸分析

随着JIT编译期的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。

  • 栈上分配:将堆分配转化为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会发生逃逸,对象可能是栈上分配的候选,而不是堆上分配

  • 同步省略:如果一个对象被发现只有一个线程被访问到,那么对于这个对象的操作可以不考虑同步。

  • 分离对象或标量替换:有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。

    就会把这个对象拆解成若干个其中包含的若干个成员变量来代替.这个过程就是标量替换

方法区

“尽管所有的方法区在逻辑上是属于堆的一部分,但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩

方法区主要存放的是 Class,而堆中主要存放的是 实例化的对象

  • 加载大量的第三方的jar包

  • Tomcat部署的工程过多(30~50个)

  • 大量动态的生成反射类

常量池中有什么
  • 数量值

  • 字符串值

  • 类引用

  • 字段引用

  • 方法引用

运行时常量池(Runtime Constant Pool)是方法区的一部分。

常量池表(Constant Pool Table)是Class文件的一部分,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中

运行时常量池,相对于Class文件常量池的另一重要特征是:具备动态性

StringTable为什么要调整位置

stringTable回收效率不高。而我们开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足。放到堆里,能及时回收内存。

静态变量存放在那里?

静态引用对应的对象实体始终都存在堆空间

方法区的垃圾收集主要回收两部分内容:常量池中废弃的常量和不再使用的类型。

只要常量池中的常量没有被任何地方引用,就可以被回收

对象实例化内存布局与访问定位

对象的实例化

对象头包含了两部分,分别是 运行时元数据(Mark Word)和 类型指针

运行时元数据
  • 哈希值(HashCode)

  • GC分代年龄

  • 锁状态标志

  • 线程持有的锁

  • 偏向线程ID

  • 偏向时间戳

类型指针

指向类元数据InstanceKlass,确定该对象所属的类型。指向的其实是方法区中存放的类元信息

实例数据(Instance Data)

对齐填充说明

不是必须的,也没有特别的含义,仅仅起到占位符的作用

StringTable

注意

字符串常量池是不会存储相同内容的字符串的

String的string Pool是一个固定大小的Hashtable,默认值大小长度是1009。如果放进string Pool的string非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用string.intern时性能会大幅下降。

使用-XX:StringTablesize可设置stringTab1e的长度

字符串拼接操作

  • 常量与常量的拼接结果在常量池,原理是编译期优化

  • 常量池中不会存在相同内容的变量

  • 只要其中有一个是变量,结果就在堆中。变量拼接的原理是StringBuilder

  • 如果拼接的结果调用intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址

从上述的结果我们可以知道:

如果拼接符号的前后出现了变量,则相当于在堆空间中new String(),具体的内容为拼接的结果

而调用intern方法,则会判断字符串常量池中是否存在JavaEEhadoop值,如果存在则返回常量池中的值,否者就在常量池中创建

s1 + s2的执行细节

  • StringBuilder s = new StringBuilder();

  • s.append("a");

  • s.append("b");

  • s.toString(); -> 类似于new String("ab");

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

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

相关文章

VS Code C++可视化调试配置Natvis,查看Qt、STL变量内容

VS Code C可视化调试配置Natvis 使用GlobalVisualizersDirectory Windows下 C:\Users\YourName\.vscode\extensions\ms-vscode.cpptools-1.18.5-win32-x64\debugAdapters\vsdbg\bin\Visualizers\Linux下 ~\.vscode\extensions\ms-vscode.cpptools-1.18.5-win32-x64\debugAd…

Spring Cloud 原理(第一节)

一、百度百科 Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等&#xff0c;都可以用Spring Boot的开发风格做到一键启动和部署。Spri…

实验五 C语言函数程序设计习题 (使用函数计算两点间的距离,请编写函数fun,使用函数输出字符矩阵,使用函数求最大公约数和最小公倍数)

1. 使用函数计算两点间的距离&#xff1a;给定平面任意两点坐标(x1,y1)和(x2,y2)&#xff0c;求这两点之间的距离(保留2位)小数。要求定义和调用dist(x1,y1,x2,y2)计算两点间的距离。坐标中两点坐标之间的距离公式如下&#xff1a; #include <stdio.h> #include <math…

1.ORB-SLAM3中如何保存多地图、关键帧、地图点到二进制文件中

1 保存多地图 1.1 为什么保存(视觉)地图 因为我们要去做导航&#xff0c;导航需要先验地图。因此需要保存地图供导航使用&#xff0c;下面来为大家讲解如何保存多地图。 1.2 保存多地图的主函数SaveAtlas 2051 mStrSaveAtlasToFile是配置文件中传递的参数&#xff1a; 这里我们…

ssh远程连接阿里云CentOS:修改为密码登录

文章目录 控制台添加密钥下载Xshell修改密码连接重启服务&#xff1a;重复Xshell使用密码登录 控制台添加密钥 会下载一个pem文件 下载Xshell 新建 通过public key登录 修改密码连接 passwd root然后输入你想要设置的密码两遍 cd /etc/ssh/ vi sshd_config将PasswordAuth…

[论文精读]利用大语言模型对扩散模型进行自我修正

本博客是一篇最新论文的精读&#xff0c;论文为UC伯克利大学相关研究者新近(2023.11.27)在arxiv上上传的《Self-correcting LLM-controlled Diffusion Models》 。 内容提要: 现有的基于扩散的文本到图像生成模型在生成与复杂提示精确对齐的图像时仍然存在困难,尤其是需要数值和…

生成对抗网络(DCGAN)手写数字生成

文章目录 一、前言二、前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09; 二、什么是生成对抗网络1. 简单介绍2. 应用领域 三、创建模型1. 生成器2. 判别器 四、定义损失函数和优化器1. 判别器损失2. 生成器损失 五、定义训练循环六、训练模型七、创建 G…

“前端八股文背诵版“,终于整理完了,堪称最强!

随着互联网的快速发展&#xff0c;前端开发领域成为了IT行业中的热门领域之一。很多求职者都希望能够进入这个领域&#xff0c;但是面对着如此激烈的竞争&#xff0c;很多人都感到无从下手。为了帮助大家更好地掌握前端开发的相关知识&#xff0c;小编整理了一份前端面试题合集…

单片机怎么实现真正的多线程?

单片机怎么实现真正的多线程? 不考虑多核情况时&#xff0c;CPU在一个时间点只能做一件事&#xff0c;因为切换的速度快所以看起来好像是同时执行多个线程而已。 实际上就是用定时器来做时基&#xff0c;以时间片的方式分别执行来实现的&#xff0c;只不过实现起来细节比较复…

网络安全应急响应-Server2228(环境+解析)

网络安全应急响应 任务环境说明: 服务器场景:Server2228(开放链接)用户名:root,密码:p@ssw0rd123

【代码】考虑差异性充电模式的电动汽车充放电优化调度matlab-yalmip-cplex/gurobi

程序名称&#xff1a;考虑差异性充电模式的电动汽车充放电优化调度 实现平台&#xff1a;matlab-yalmip-cplex/gurobi 代码简介&#xff1a;提出了一种微电网中电动汽车的协调充电调度方法&#xff0c;以将负荷需求从高峰期转移到低谷期。在所提出的方法中&#xff0c;基于充…

RHEL8.9 静默安装Oracle19C

RHEL8.9 静默安装Oracle19C 甘肃圆角网络科技开发有限公司 说明(GUI)&#xff1a;  1.实际业务场景中&#xff0c;Linux环境一般情况下是没有GUI的。没有GUI并不意味着没有安装图形界面。可能在部署Linux操作系统环境的时候安装了桌面环境&#xff0c;只是启动的时候设置了启动…

英国人工智能初创公司Stability AI面临卖身压力;深度学习中的检索增强生成简介

&#x1f989; AI新闻 &#x1f680; 英国人工智能初创公司Stability AI面临卖身压力 摘要&#xff1a;多位知情人士透露&#xff0c;英国人工智能初创公司Stability AI正寻求出售公司&#xff0c;因为投资者对其财务状况的压力越来越大。管理层最近几周一直将自己标榜为收购…

MapInfo Pro错误提示:This operation requires elevated privileges……

尝试删除MapInfo Pro时出现错误“此操作需要提升权限。将产品DVD/CD插入媒体播放器并双击setup.exe文件重新启动。此安装程序现在将中止。”。 原因&#xff1a; 这可能是由于权限问题。 解决方式&#xff1a; 1.如果MapInfo Pro setup.exe可用&#xff0c;请执行以下步骤&…

笔记64:Bahdanau 注意力

本地笔记地址&#xff1a;D:\work_file\&#xff08;4&#xff09;DeepLearning_Learning\03_个人笔记\3.循环神经网络\第10章&#xff1a;动手学深度学习~注意力机制 a a a a a a a a a a a

FIORI /N/UI2/FLP 始终在IE浏览器中打开 无法在缺省浏览器中打开

在使用/N/UI2/FLP 打开fiori 启动面板的时候&#xff0c;总是会在IE浏览器中打开&#xff0c;无法在缺省浏览器打开 并且URL中包含myssocntl 无法正常打开 启动面板 这种情况可以取消激活ICF节点/sap/public/myssocntl

spring boot 3.2.0 idea从零开始

spring boot 3.2.0 idea从零开始 最新的spring initilizer 不再支持低版本java&#xff0c;只能选择17、21 。 我也被迫尝试下最新版本的java。 jdk下载地址 自定义好artifact和group之后点击下一步。 在这里选择需要的组件&#xff0c;我准备做web项目所以只选择spring web …

word模板导出word文件

前期准备工作word模板 右键字段如果无编辑域 ctrlF9 一下&#xff0c;然后再右键 wps 直接 ctrlF9 会变成编辑域 pom.xml所需依赖 <dependencies> <!--word 依赖--> <dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId…

vim工具以及如何给用户加上sudo的权限

Linux开发工具之vim以及如何给用户配置sudo的权限文件的操作 1.vim概念的介绍 2.vim的多模式的介绍 3.vim的命令模式与低行模式的相关指令操作 4.vim如何配置 5.如何给普通用户配置sudo的权限 本文开始~~~~ 1. vim概念的介绍 vim是一款多模式的文本编辑器&#xff0c;简单…

C语言-指针讲解(4)

在上一篇博客中&#xff1a; C语言-指针讲解(3) 我们给大家介绍了指针进阶的用法 让下面我们来回顾一下讲了什么吧&#xff1a; 1.字符指针变量类型以及用法 2.数组指针本质上是一个指针&#xff0c;里面存放数组的地址。而指针数组本质上是个数组&#xff0c;里面存放的是指针…