JVM类加载与运行时数据区

news2024/12/25 15:03:44

目录

一、类加载器

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 stats
                    sun.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.coloradmin.cn/o/1273771.html

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

相关文章

计算机软件的分类

以功能进行分类&#xff0c;计算机软件通常可以分为系统软件和应用软件两大类。 系统软件&#xff1a;系统软件是计算机运行和管理的基本软件&#xff0c;包括操作系统、驱动程序、系统工具和服务程序等。操作系统是系统软件的核心&#xff0c;负责管理计算机的硬件资源、提供用…

亚信科技AntDB数据库完成中国信通院数据库迁移工具专项测试

近日&#xff0c;在中国信通院“可信数据库”数据库迁移工具专项测试中&#xff0c;湖南亚信安慧科技有限公司&#xff08;简称&#xff1a;亚信安慧科技&#xff09;数据库数据同步平台V2.1产品依据《数据库迁移工具能力要求》、结合亚信科技AntDB分布式关系型数据库产品&…

常见智力题汇总

常见智力题汇总 扔瓶子问题扑克牌问题出队问题烧绳子问题赛马问题求出前三名求出前五名 接水问题种树问题硬币问题宝石问题核酸检测问题 笔者最近面试遇到了好几道智力题&#xff0c;这些题目特点就是如果没有见过&#xff0c;很难第一时间思考得到答案&#xff0c;因此笔者面试…

CISO在2024年应该优先考虑七项安全任务

专业安全媒体CyberTalk.org主编Shira Landau日前表示&#xff1a;现代企业的CISO们在2024年必须做出改变&#xff0c;要更多关注于企业整体安全路线图的推进与实现&#xff0c;让网络安全工作与业务发展目标保持更紧密的一致性。 首席信息安全官&#xff08;CISO&#xff09;是…

模拟算法【3】——1419.数青蛙

文章目录 &#x1f365;1. 题目&#x1f96e;2. 算法原理&#x1f361;3. 代码实现 &#x1f365;1. 题目 题目链接&#xff1a;1419. 数青蛙 - 力扣&#xff08;LeetCode&#xff09; 给你一个字符串 croakOfFrogs&#xff0c;它表示不同青蛙发出的蛙鸣声&#xff08;字符串 &…

WPS导出的PDF比较糊,和原始的不太一样,将带有SVG的文档输出为PDF

一、在WPS的PPT中 你直接输出PDF可能会导致一些问题&#xff08;比如照片比原来糊&#xff09;/ 或者你复制PPT中的图片到AI中类似的操作&#xff0c;得到的照片比原来糊&#xff0c;所以应该选择打印-->高级打印 然后再另存为PDF 最后再使用AI打开PDF文件再复制到你想用…

JSP+servlet实现高校社团管理系统

JSPservlet实现的高校社团管理系统 &#xff0c;前后台都有&#xff0c;前台演示地址:高校社团管理系统 后台演示地址:登录 用户名:sys,密码:123456 前台功能&#xff1a;首页&#xff0c;社团列表&#xff0c;社团风采&#xff0c;社团活动&#xff0c;新闻列表&#xff0c…

Vue中 env 文件是如何读取的? 优先级?

Vue中 env 文件是如何读取的&#xff1f; 优先级&#xff1f; start 今天来研究一下 Vue 中 env 是如何读取的。跟着我的脚步来学习一下吧。作者&#xff1a;番茄&#xff1b;编写时间&#xff1a;2023/11/30 前情提要 env&#xff0c;使用方式是process.env。简单来说&…

单链表相关经典算法OJ题:移除链表元素

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 题目&#xff1a;移除链表元素 解法一&#xff1a; 解法一的代码实现&#xff1a; 解法二&#xff1a; 解法二代码的实现&#xff1a; 总结 前言 世上有两种耀眼的…

element中el-form-item设置label-width=‘auto‘报错

文章目录 一、问题二、解决三、最后 一、问题 el-form中的设置了全局标题宽度是200px&#xff0c;此时想要对el-form-item取消标题宽度&#xff0c;设置了label-widthauto&#xff0c;结果&#xff0c;报错了~~~ <el-form label-width"200px" label-position&quo…

IOS/安卓+charles实现抓包(主要解决证书网站无法打开问题)

安装 官网下载 https://www.charlesproxy.com/latest-release/download.do 安装charles文档 流程 上述链接解决下图问题 使用介绍 Charles介绍 上述链接看一至三即可&#xff0c;了解首页各个按钮的作用 charles全面使用教程及常见功能详解&#xff08;较详细&#xff09…

【MATLAB源码-第92期】基于simulink的QPSK调制解调仿真,采用相干解调对比原始信号和解调信号。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 QPSK&#xff0c;有时也称作四位元PSK、四相位PSK、4-PSK&#xff0c;在坐标图上看是圆上四个对称的点。通过四个相位&#xff0c;QPSK可以编码2位元符号。图中采用格雷码来达到最小位元错误率&#xff08;BER&#xff09; —…

【开源】基于Vue+SpringBoot的服装店库存管理系统

项目编号&#xff1a; S 052 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S052&#xff0c;文末获取源码。} 项目编号&#xff1a;S052&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 角色管理模块2.3 服…

将class文件反编译成java文件

一、IDEA自带的Java Bytecode Decompiler 对于需反编译的class文件Kb比较大时&#xff0c;反编译后的文件就会报一大堆错误&#xff0c;适用于小Kb或者比较简单的class反编译 二、Jad jad是一个简单易用的命令行工具&#xff0c;适合快速简单的反编译任务 1.Jad下载地址 htt…

万宾科技监测设备,可燃气体监测仪特点一览

万宾科技的监测设备种类繁多&#xff0c;包括可燃气体监测仪、管网水位监测仪、内涝积水监测仪等。其中可燃气体监测仪是万宾科技的核心产品之一&#xff0c;用于监测环境中可燃气体的浓度&#xff0c;适用于对甲烷气体浓度进行实时监测&#xff0c;应用于燃气管网、排水管网、…

Python实验项目8 :科学计算与可视化

1&#xff1a;创建 numpy 数组。 要求&#xff1a; &#xff08;1&#xff09;使用 array()函数、empty()函数、zeros()函数、linspace()函数等创建 numpy 数组。 &#xff08;2&#xff09;使用 numpy 数组的索引和切片方法访问数组元素。 # 要求&#xff1a; # &#xff0…

MJPG-streamer方案实现物联网视频监控

目录 前言 一、JPEG&#xff0c;MJPG格式简介 JPEG MJPG MJPG的优点 MJPG的缺点 二、软硬件准备 三、编译MJPG-streamer 四、运行MJPG-streamer 五、其它常见用法 六、MJPG-streamer 程序框架 七、源码下载 前言 最近想做一个安防相关的项目&#xff0c;所以跟着韦…

ios 逆向分分析,某业帮逆向算法(一)

用到工具: 爱思助手CrackerXL(砸壳软件)越狱手机ida反汇编软件分析login 的sign 签名算法中自己写算法 已知我们32位,我们不妨猜测是md5 ,那我们试图使用CC_MD5 ,这个是ios 中的标准库, 我们使用frida-trace 注入hook一下,看看有没有 经过 是经过了这个函数,密码也是…

动态规划--整数拆分

题目描述 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入: n 2 输出: 1 解释: 2 1 1, 1 1 1。 示例 2: 输入: n 10 输出: 36 解释…

寿险公司通过开源治理保障数字创新,安全打通高质量服务新通道

某寿险公司致力于为消费者提供人性化的产品和服务&#xff0c;在中国保险市场中始终保持前列。该寿险公司以挖掘和满足客户需求为出发点&#xff0c;从产品开发、渠道销售、运营流程和售后服务等各环节&#xff0c;借助数字化工具&#xff0c;不断地努力探索并提升服务品质。 精…