[JVM] 2. 类加载子系统(1)-- 内存结构、类加载子系统概述

一、内存结构

类加载子系统的职责是:加载class文件到内存中。

完整的内存结构如下:

二、类加载过程

类加载过程总体分为Loading(加载)、Linking(链接)、Initialization(初始化)三个环节,在Linking阶段又细分为Verification(验证)、Preparation(准备)、Resolution(解析)三个环节。

1. 加载(Loading)

  • 通过一个类的全限定名获取定义此类的二进制字节流
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

补充:加载class文件的方式

  • 从本地系统中直接加载
  • 通过网络获取,典型场景:Web Applet
  • 从zip压缩包中读取,成为日后jar、war格式的基础
  • 运行时计算生成,使用最多的是:动态代理技术
  • 由其他文件生成,典型场景:JSP应用
  • 从专有数据库中提取.class文件,比较少见
  • 从加密文件中获取,典型的防Class文件被反编译的保护措施

2. 链接(Linking)

(1)验证(Verification)

  • 验证字节码文件的字节流中包含信息符合虚拟机规范,以防止不正常的字节流危害虚拟机安全。所有能被JVM识别的字节码文件,它的有效起始都是CA FE BA BE,它是JVM识别的一个标识。
  • 主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
  • 验证错误会报VerifyError

        我们使用BinaryViewer打开.class文件,发现他的开头都是 CAFE BABE。

(2)准备(Preparation)

  • 为类变量(非final修饰的static变量)分配内存(在方法区),设置其初始值(零值)
  • 如果 static 变量是 final 的基本类型,以及字符串常量,那么编译阶段值就确定了,赋值在准备阶段完成
  • 如果 static 变量是 final 的引用类型,即new的对象,赋值在初始化阶段完成
  • 实例变量不会被分配初始化,实例变量随对象被分配到Java堆中。

(3)解析(Resolution)(存疑)

  • 将常量池内的符号应用转换为直接引用。
  • 符号引用是一组来描述所引用的目标。直接引用就是直接指向目标的指针、相对偏移量或者一个间接定位到目标的句柄。

3. 初始化(Initialization)

        (1)初始化阶段就是执行类构造器方法<clinit>()的过程。此方法不需定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。

        也就是说,没有类变量和静态代码块,就不会有<clinit>,比如下面这段代码:

        在字节码文件中,一个类的方法会被解析到methods文件目录下,构造器对应目录下的<init>()方法, main()就对应main()。

        我们使用idea的jclasslib插件查看method,发现只有类构造器<init>和main方法。

        (2)构造器方法中指令按语句在源文件中出现的顺序执行。

        结合如下代码进行理解:

        1. 我们在静态代码块中使用了类变量number,但是number的定义是在整个静态代码块之后,能这样做的原因是,在链接的准备阶段,我们已经为number分配了内存,并设置初始值为0.

        2. 但是不能在声明之前进行引用。

        使用jclasslib查看<clinit>的代码,如下:

        这串代码是与文件里语句的顺序对应起来的。

         因此执行这段代码后,number的值应该是10,而不是20.

        (3)若该类具有父类,JVM会保证子类的<clinit>()执行前,父类的<clinit>()已经执行完毕。

        (4)虚拟机必须保证一个类的<clinit>()方法在多线程下被同步加锁。

        以这段代码为例,尝试多线程加载一个类。

        执行这段代码的结果是,永远会有一个线程无法结束,因为<clinit>只会有一次,也就是说类只能被加载一次。

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

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

相关文章

HarmonyOS学习路之方舟开发框架—学习ArkTS语言(基本语法 五)

Styles装饰器&#xff1a;定义组件重用样式 如果每个组件的样式都需要单独设置&#xff0c;在开发过程中会出现大量代码在进行重复样式设置&#xff0c;虽然可以复制粘贴&#xff0c;但为了代码简洁性和后续方便维护&#xff0c;我们推出了可以提炼公共样式进行复用的装饰器St…

一文读懂 MySQL 中的索引

文章目录 1. 索引概述1.1 索引概述1.2 优点1.3 缺点1.6 常见索引概念1.6.1 聚簇索引1.6.2 二级索引&#xff08;辅助索引、非聚簇索引&#xff09;1.6.3 联合索引 1.8 MyISAM索引的原理1.9 MyISAM 与 InnoDB对比1.10 索引的代价 2. 索引的创建与设计原则2.1 索引的声明与使用2.…

一文9个步骤带你从0到1入门接口自动化测试!

1.请问你是如何做接口测试的&#xff1f; 大体来说&#xff0c;经历以下过程&#xff1a;接口需求调研、接口测试工具选择、接口测试用例编写、接口测试执行、接口测试回归、接口测试自动化持续集成。 具体来说&#xff0c;接口测试流程分成以下九步&#xff1a; 第一步&…

6.3.6 利用Wireshark进行协议分析(六)----网页提取过程的协议分析

6.3.6 利用Wireshark进行协议分析&#xff08;六&#xff09;----网页提取过程的协议分析 利用Wireshark捕获网页访问过程中产生的应用协议报文&#xff0c;还原Web服务中报文的交互过程&#xff0c;为了防止网页直接从本地缓存中获取&#xff0c;我们首先需要清空浏览器保存的…

el-date-picker 宽度溢出浏览器问题

原文链接&#xff1a; el-date-picker 宽度溢出浏览器问题 问题由来 <el-date-picker v-model"Time" type"datetimerange"range-separator"至"start-placeholder"年/月/日 时:分:秒"end-placeholder"年/月/日 时:分:秒"…

Js: 读取数据并动态生成表格(读取新数据时,应该删除之前已经渲染出来的数据)

前言 使用JS读取数据并动态生成表格&#xff0c;但是发现在读取新一轮的数据时&#xff0c;新数据是在之前已经渲染的数据后面进行追加。因此需要解决的问题是&#xff1a;在读取新数据之前&#xff0c;把之前已经渲染的数据进行清空。 解决 1、首先写出表格的表头和主干 &…

堆排序+TopK问题

本期带大家学习堆排序TopK问题&#x1f308;&#x1f308;&#x1f308; 1、堆排序 堆排序&#xff0c;是根据堆的结构而设计出的一种排序算法&#xff0c;其时间复杂度&#xff1a;O(N * logN)&#xff0c;空间复杂度&#xff1a;O(1)。 堆排序的前提是需要 构建一个堆&…

Postman接口自动化之postman脚本编写

这是之前搞的接口自动化方案&#xff0c;已经在业务测试中实现了使用postman编写接口脚本&#xff0c;通过GitHubJenkinsemail html report实现了接口自动化&#xff0c;现在分块整理一下。 postman脚本编写 1、创建集合 和 目录&#xff1a; 一条业务线下的接口可以放到一个…

微信小程序中常见组件的使用

文章目录 微信小程序中常见组件的使用视图组件viewscroll-viewswipermovable-area 基础组件icontextrich-textprogress 表单组件buttoncheckbox、checkbox-grouplabelforminputpicker单列选择器多列选择器时间选择器&日期选择器&地区选择器 picker-viewradiosliderswit…

(简单)剑指Offer 21. 调整数组顺序使奇数位于偶数前面 Java

记数组nums的长度为n。从先nums左侧开始遍历&#xff0c;如果遇到的是奇数&#xff0c;就表示这个元素已经调整完成&#xff0c;继续从左往右遍历&#xff0c;直到遇到一个偶数。然后从nums右侧开始遍历&#xff0c;如果遇到的是偶数&#xff0c;就表示这个元素已经调整完成了&…

如何有效跟踪员工时间:时间管理方法和工具

许多人认为时间追踪是一件麻烦事&#xff0c;会分散他们对主要职责的注意力。 员工不喜欢填写工时表&#xff0c;也不喜欢受到额外的监督&#xff1b;对于管理者来说&#xff0c;时间跟踪始终是一项额外的工作&#xff0c;要确保所有员工正确、按时地填写工时表。 但无论如何…

Ubuntu开机自启动设置

一、创建执行脚本 这里有两个程序所以编写了两个脚本&#xff0c;第一脚本(master.sh)&#xff1a; gnome-terminal -- bash -c "source /home/zyy/anaconda3/bin/activate wood2;cd /home/zyy/pycharmProject/master_program;python main.py > /home/zyy/pycharmProj…