当前位置: 首页 > 编程日记 > 正文

《深入java虚拟机》读书笔记类加载

概述

类加载机制是指虚拟机将描述类的数据从Class文件中加载到内存,并进行数据验证、解析、初始化等过程,最后形成可以直接被虚拟机使用的java类型。在java语言中类的加载、链接、初始化等过程并不是在编译时期完成,而是在运行时期才进行的,这样做的好处在于可以为语言提供了动态扩展的特性(可以在运行期间动态接收二进制的字节码文件解析运行),坏处在于增加了性能的开销。

类加载过程

类在jvm中的整个生命周期包括:

加载(loading)-->验证(verification)-->准备(preparation)-->解析(resolution)-->初始化(initialization)-->使用(using)-->卸载(unloading)

其中验证、准备、解析并称为链接阶段。并且加载、验证、准备、解析、初始化阶段的开始时机是确定的,当然这里不需要等待前一个完成才执行后一个。而解析过程则不一定了,因为Java语言可能会存在运行时动态解析。

加载

加载过程实际上就是通过二进制字节流生成Class对象的过程,整个过程可以分为以下阶段:

  1. 通过类的全限定名来获取定义该类二进制字节流,这里的字节流并不要求一定是从Class文件获取,可以从压缩包(jar,war)、其他文件生成(jsp)、网络、计算生成(proxy)等等途径获得。
  2. 将这个字节流所表示的静态存储结构转换为方法去的动态运行时数据结构。数据存储格式由虚拟机自行实现。
  3. 在内存中实例化一个java.lang.Class对象,作为方法区中该类的数据访问入口。在HotSpot虚拟机中,Class对象在JDK1.7前是存储在方法区中,在JDK1.7之后Class实例存放在堆中。

在加载过程中的获取二进制字节流阶段既可以使用JDK提供了类加载器进行加载,也可以使用我们自定义的类加载器加载。但是如果是加载一个数组类就有些不一样了。

数组类本身并不通过类加载器加载,其由虚拟机直接创建,但是数组中承载的对象还是由类加载器加载:

如果数组类承载的对象时引用类型那么就递归(数组可以嵌套)的调用加载过程对类进行加载,同时该数组将在加载被承载对象的类加载器的类名称空间中被标识。如果数组中的内容并不是引用类型(基本数据类型),那么Java虚拟机将会将该数组标记为与引导类加载器关联。

验证

验证是链接过程的开始,这一阶段的目的是为了保证Class文件的字节流中包含的信息符合虚拟机的要求,并且不会危害虚拟机的安全。

在加载一节我们说过二进制的字节流并不一定必须是通过java代码编译而来,统一通过多种形式,甚至可以直接使用十六进制数据构造。所以我们必须要对数据进行验证,否则随意的数据可能导致虚拟机崩溃。在java虚拟机规范中对数据的约束和规范规则较多,大致可以分为4种:

  1. 文件格式验证:主要验证字节流是否符合Class文件规范以及能否被当前版本的虚拟机处理,包括魔数验证,版本号等等。目的是为了保证输入的字节流能够正确的解析和存储于方法区内,在格式上符合描述一个java类型信息的要求。通过验证后,会将字节流信息存储于内存中的方法区中。
  2. 元数据验证:对字节码描述的信息进行语义分析,保证不存在不符合java语言规范的元数据。如该类是否有父类,父类是否继承了不允许继承的类等等。
  3. 字节码验证:通过数据流和控制流来确定程序语义是否是合法的、符合逻辑的。该阶段是对类的方法体进行校验。例如保证指令的跳转不会跳到方法体外的字节码指令上,保证类型转换时有效地等等。但是即使通过了字节码验证也并不能表示程序就是绝对无措的。因为我们的检验程序的程序本身是可能有错或不足的。
  4. 符号引用验证:该验证是在解析阶段进行的(类加载的过程可能是相互交叉的)。符号引用验证的目的是为了确保解析动作能正常执行。如果无法通过符号引用验证,像java.lang.NoSuchMethodError等都是在该阶段抛出的。

需要注意的是该校验并不是每一次都需要的,假设我们的程序在测试环境下多次测试都是正常的,那么我们在生产环境下可以通过-Xverify:none参数来关闭大部分的验证措施,用以提高虚拟机的类加载时间。

准备

准备阶段是正式为类变量分配内存和设置类变量初始值的阶段,这些变量所需的内存都是你在方法区进行分配。

需要注意的是这里分配内存的仅仅是类变量(static)而不包括实例变量。实例变量内存分配和赋初值是在对对象实例化阶段进行的。同时这里的赋初值也并不是设置我们在程序中定义好的值,而是零值,比如int类型的零值为0,应用类型零值为null。

但是如果是constantValue(同时被final和static进行修饰)的值则是在该阶段进行赋值的,其他类型正式赋值是在初始化阶段进行的。

解析

解析是虚拟机将常量池中的符号引用替换为直接引用的过程。解析主要的对类,接口,字段,类方法,接口方法,方法类型等符引用进行。

  • 符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任意形式的字面量,只要使用时能够无歧义的定位到目标即可。
  • 直接引用:直接引用可以是直接指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。

初始化

初始化过程实际上就是对变量赋值(不是赋初值)的过程。包含所有类变量的赋值以及静态代码语句块的执行代码,包括对父类的初始化。

类加载器

在前面的加载过程中有说到“通过类的全限定名来获取该类的二进制字节码流”,这一过程的实现就是通过类加载器完成的。

类与类加载器

对于任意的一个类,都需要由该类本身和加载该类的类加载器来确定其在Java虚拟机中的唯一性,每一个类加载器都有一个独立的类名称空间。这句话的意思就是要判断两个类是否一样,不能仅仅比较两个类是否通过同一个Class文件生成的,假如两个类通过同一个Class文件生成但是各自加载他们的类加载器不一样,那么这两个类也是不相等的,在使用equals方法和instanceof关键字等时都遵循这个原则。

几种类加载器

这里介绍几种已经内置的类加载器(都是针对于HotSpot vm):

  • BootStrap ClassLoader(启动类加载器):该类加载器负责加载<JAVA_HOME>/lib目录和由-Xbootclasspath参数指定的路径下的类库。但是并不是说把任意类库放在lib目录下都会被加载,必须是虚拟机内定义好的名字的类库。同时在HotSpot VM中BootStrap ClassLoader是由C++实现,所以在java程序中我们无法获取到该类加载器的实例,如果我们自定义的类加载器中需要用到BootStrap ClassLoader的话可以直接使用null代替。
  • Extension ClassLoader(扩展类加载器):该类加载器负责加载<JAVA_HOME>/lib/ext目录下或者由java.ext.dirs变量指定的路径下的类库,该类加载器我们可以直接使用。
  • Application ClassLoader(应用类加载器):该类加载器负责加载用户路径(ClassPath)下的类库。该类加载器也是默认的类加载器。

我们也可以继承ClassLoader类并重写findClass方法进行自定义类加载器。

双亲委派模型(Parents Delegation Model)

上面介绍的不同类加载器之间也并不是各自独立运作的,其相互之间存在着一些关系。

像上图这种层级关系被称为双亲委派模型,双亲委派模型是如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时,子加载器才会尝试自己去加载。实际上双亲委派模型的并不是指每一个类加载器都有两个父加载器,parents是指可以有多个父加载器,当然也可以只有一个。这里的翻译有点怪怪的。

双亲委派模型的好处在于通过不同层次的类加载器加载的类先天的带有一个层次关系,保证同一个类不会被多次加载,例如类java.lang.Object,它由启动类加载器加载。双亲委派模型保证任何类加载器收到的对java.lang.Object的加载请求,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。

双亲委派模型的实现:

protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {Class<?> c = findLoadedClass(name);//如果该类没有被加载则通过类加载器加载//已经被加载就返回if (c == null) {long t0 = System.nanoTime();try {//判断父加载器是否为空 为空表示使用BootStrap ClassLoader加载if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {//父加载器无法加载该类 下面有当前类加载器自己加载}if (c == null) {long t1 = System.nanoTime();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) {resolveClass(c);}return c;}}
复制代码

双亲委派模型并不是一个强制性的约束,我们的实现理论上可以不遵循该模型理论。如果有必要的话可能会对双亲委派模型进行破坏(让父类加载器主动将类加载行为交给子类进行或者直接由当前类加载器加载不交给父类),比如JNDI,OSGI等。

相关文章:

SLAM之特征匹配(一)————RANSAC-------OpenCV中findFundamentalMat函数使用的模型

目录 1.RANSAC原理 2. RANSAC算法步骤&#xff1a; 3. RANSAC源码解析 step one niters最初的值为2000&#xff0c;这就是初始时的RANSAC算法的循环次数&#xff0c;getSubset&#xff08;&#xff09;函数是从一组对应的序列中随机的选出4组&#xff08;因为要想计算出一…

I hope so 2016-Oct-10

2019独角兽企业重金招聘Python工程师标准>>> <I hope so> - A joke A: Do you think your son will forget all he learned at college? B: I hopse so. He certainly cant make a living by kissing girls! 转载于:https://my.oschina.net/u/553266/blog/75…

【Codeforces】158B-Taxi(贪心,怎么贪咧)

贪心 emmmm http://codeforces.com/contest/158/problem/B 题目大意&#xff1a;有四种旅客&#xff0c;四人一组&#xff0c;三人一组&#xff0c;两人一组&#xff0c;一人一组&#xff0c;一辆出租车最多可以坐四个人&#xff0c;并且一组里的人必须坐一辆车&#xff0c…

90 后 CTO 创业 6 年,做了一件改变互联网的“小事”

TGO 鲲鹏会在武汉举行了一场线下分享活动 —— 冲破壁垒&#xff0c;打造精英的技术团队 。来自极验的 90 后 CTO 黄胜蓝分享了他的团队故事&#xff0c;以及在他看来一个创新团队应该具备的特征。极验 CTO \u0026 TGO 鲲鹏会会员黄胜蓝在现场进行分享 1. 创新&#xff1a;非典…

ORB特征(二)

为了满足实时性的要求&#xff0c;前面文章中介绍过&#xff08;具体链接如下&#xff09;快速提取特征点算法Fast,以及特征描述子Brief。本篇文章介绍的ORB算法结合了Fast和Brief的速度优势&#xff0c;并做了改进&#xff0c;且ORB是免费Ethan Rublee等人2011年在《ORB&#…

【POJ】2377 Bad Cowtractors(最大生成树)

简单题&#xff0c;模板题 求解最大生成树&#xff0c;提交一直WA&#xff0c;感觉没有什么问题啊&#xff0c;就是在求解最小生成树的模板基础上稍加修改即可&#xff0c;后来发现在输出a&#xff0c;b&#xff0c;c给map二维数组的时候还必须有判断条件&#xff0c;略为有点…

使用let替换var实现块级作用域的小发现

在讲述javascript没有块级作用域的时候都会提到一个非常经典的例子&#xff1a; var obj{name:helo,age:15 }; var arr[];for(var i0;i<5;i){arr[i]i;console.log(i);} console.log(arr); console.log(i);因为javascript没有块级作用域&#xff0c;所以控制台打印出来的结果…

windows系统下node、npm的安装和卸载

Greta有话说&#xff1a;我是在有道云笔记只弄个记录的笔记&#xff0c;粘贴过来之后&#xff0c;没有图片&#xff0c;我的笔记地址为&#xff1a; 有道云笔记&#xff0c;请点我   一、卸载 1、node.js、nvm、 npm &#xff08;1&#xff09;在cmd中输入where node找到node…

OpenCV4Android开发实录(2): 使用OpenCV3.4.1库实现人脸检测

OpenCV4Android开发实录(2)&#xff1a; 使用OpenCV3.3.0库实现人脸检测 转载请声明出处&#xff1a;http://write.blog.csdn.net/postedit/78992490OpenCV4Android系列&#xff1a; 1. OpenCV4Android开发实录(1)&#xff1a;移植OpenCV3.3.0库到Android Studio 2.OpenCV4Andr…

活动|跟着微软一起,拥抱开源吧!

由开源社主办的中国开源年会2016 (COSCon16 - China Open Source Conference 2016) 即将于今年10月15日-16日在北京举办。微软大咖将为您呈现区块链&#xff0c;容器&#xff0c;大数据&#xff0c;Xamarin等时下热点技术&#xff0c;参会者还可获取价值1,500 元 Azure 服务使用…

【HDU/算法】最短路问题 杭电OJ 2544 (Dijkstra,Dijkstra+priority_queue,Floyd,Bellman_ford,SPFA)

最短路径问题是图论中很重要的问题。 解决最短路径几个经典的算法 1、Dijkstra算法 单源最短路径&#xff08;贪心&#xff09;&#xff0c;还有用 priority_queue 进行优化的 Dijkstra 算法。 2、bellman-ford算法 例题&#xff1a;【ACM】POJ 3259 Wormholes 允许负权边…

javaSE基础知识 1.5整数类型

整数的四种声明类型它们分别是&#xff0c;byte&#xff0c;short&#xff0c;int&#xff0c;long&#xff0c;这四种类型所占用的空间是不同的byte是占用1个字节&#xff0c;它的取值范围是 -128~127&#xff0c;short是占用2个字节&#xff0c;他的取值范围是-32768~32767&a…

源码分析-GLSurfaceView的内部实现

GLSurfaceView类是继承自SurfaceView的&#xff0c;并且实现了SurfaceHolder.Callback2接口。GLSurfaceView内部管理着一个surface&#xff0c;专门负责OpenGL渲染。GLSurfaceView内部通过GLThread和EGLHelper为我们完成了EGL环境渲染和渲染线程的创建及管理&#xff0c;使我们…

【POJ/算法】 3259 Wormholes(Bellman-Ford算法, SPFA ,FLoyd算法)

Bellman-Ford算法 Bellman-Ford算法的优点是可以发现负圈&#xff0c;缺点是时间复杂度比Dijkstra算法高。而SPFA算法是使用队列优化的Bellman-Ford版本&#xff0c;其在时间复杂度和编程难度上都比其他算法有优势。 Bellman-Ford算法流程分为三个阶段&#xff1a; 第一步&am…

进程控制概念简介 多线程上篇(三)

进程控制 进程的基本数据信息是操作系统控制管理进程的数据集合&#xff0c;这些信息就是用来控制进程的&#xff0c;此处我们说的进程控制就是进程的管理。比如进程有状态&#xff0c;那么进程的创建、终止&#xff0c;状态的切换&#xff0c;这都不是进程自主进行的&#xff…

Android OpenGL使用GLSurfaceView预览视频

Android OpenGL使用GLSurfaceView预览视频第一章 相关知识介绍在介绍具体的功能之前&#xff0c;先对一些主要的类和方法进行一些介绍&#xff0c;这样可以更好的理解整个程序1.1 GLSurfaceView在谷歌的官方文档中是这样解释GLSurfaceView的&#xff1a;An implementation of S…

【Android 基础】Animation 动画介绍和实现

转载自&#xff1a;http://www.cnblogs.com/yc-755909659/p/4290114.html1.Animation 动画类型Android的animation由四种类型组成&#xff1a;XML中alph渐变透明度动画效果scale渐变尺寸伸缩动画效果translate画面转换位置移动动画效果rotate画面转移旋转动画效果JavaCode中Alp…

【Codeforces】1111B - Average Superhero Gang Power

http://codeforces.com/problemset/problem/1111/B n 表示要输入的数据的个数 k 最每一个数据最多可以进行多少次操作 m 一共可以进行多少次操作 一次操作&#xff1a;删除这个数&#xff0c;或者给这个数加1 如果n为1的话&#xff0c;那么只要找出m和k的最小值加到那个数…

刷前端面经笔记(七)

1.描述一下渐进增强和优雅降级 优雅降级(graceful degradation)&#xff1a;一开始就构建站点的完整功能&#xff0c;然后针对浏览器测试和修复。渐进增强(progressive enhancement)&#xff1a;一开始只构建站点的最少特性&#xff0c;然后不断针对各浏览器追加功能。 2.为什么…

AR资料与连接梳理

AR引擎相关技术 ------------------------------ ARcore&#xff1a;https://developers.google.cn/ar/discover/ ARkit&#xff1a;https://developer.apple.com/arkit/ 以上重点关注&#xff0c;比较新有一些新的功能大家可以自行体验。 ARToolkithttp://www.artoolkit.orght…

Queues 队列

1. Definiation What is a queue? A queue is a list. With a queue, inseration is done at one end (known as rear) whereas deletion is performed at the other end (known as front). 2. Operations 指针对列 无法自定义队长 // array queue #include<iostream> u…

【HDU】1005 Number Sequence (有点可爱)

http://acm.hdu.edu.cn/showproblem.php?pid1005 A number sequence is defined as follows: f(1) 1, f(2) 1, f(n) (A * f(n - 1) B * f(n - 2)) mod 7. Given A, B, and n, you are to calculate the value of f(n). 直接递归求解f(n)的话&#xff0c;会MLE 在计算…

CNCF案例研究:奇虎360

公司&#xff1a;奇虎360地点&#xff1a;中国北京行业&#xff1a;计算机软件 挑战 中国软件巨头奇虎360科技的搜索部门&#xff0c;so.com是中国第二大搜索引擎&#xff0c;市场份额超过35&#xff05;。该公司一直在使用传统的手动操作来部署环境&#xff0c;随着项目数量的…

C#代码实现对Windows凭据的管理

今天有个任务&#xff0c;那就是使用C#代码实现对windows凭据管理的操作。例如&#xff1a;向windows凭据管理中添加凭据、删除凭据以及查询凭据等功能。于是乎&#xff0c;就开始在网上查找。经过漫长的查询路&#xff0c;终于在一片英文博客中找到了相关代码。经过实验&#…

Android:JNI 与 NDK到底是什么

前言 在Android开发中&#xff0c;使用 NDK开发的需求正逐渐增大但很多人却搞不懂 JNI 与 NDK 到底是怎么回事今天&#xff0c;我将先介绍JNI 与 NDK & 之间的区别&#xff0c;手把手进行 NDK的使用教学&#xff0c;希望你们会喜欢 目录 1. JNI介绍 1.1 简介 定义&…

【ACM】LightOJ - 1008 Fibsieve`s Fantabulous Birthday (找规律,找...)

https://vjudge.net/problem/LightOJ-1008 题目很好理解&#xff0c;第一行表示测试样例的个数&#xff0c;接下来输入一个大于等于1的数&#xff0c;按照格式输出这个数的坐标 蓝色的是 奇数的平方&#xff1b; 红色的是 偶数的平方&#xff1b; 黄色的是对角线&#xff1a…

Computed property XXX was assigned to but it has no setter

报错视图&#xff1a; 原因&#xff1a; 组件中v-model“XXX”&#xff0c;而XXX是vuex state中的某个变量vuex中是单项流&#xff0c;v-model是vue中的双向绑定&#xff0c;但是在computed中只通过get获取参数值&#xff0c;没有set无法改变参数值解决方法&#xff1a; 1.在co…

OpenGL 矩阵变换

origin refer :http://www.songho.ca/opengl/gl_transform.html#modelviewOpenGL 矩阵变换Related Topics: OpenGL Pipeline, OpenGL Projection Matrix, OpenGL Matrix Class Download: matrixModelView.zip, matrixProjection.zipOverviewOpenGL Transform MatrixExample: GL…

2016.8.11 DataTable合并及排除重复方法

合并&#xff1a; DataTable prosxxx; DataTable pstaryyy; //将两张DataTable合成一张 foreach (DataRow dr in pstar.Rows) { pros.ImportRow(dr); } DataTable设置主键&#xff0c;并判断重复 DataTable allpros xxx; 单列设为主键&#xff1a; //设置第某列为主键 allpros.…

【ACM】LightOJ - 1010 Knights in Chessboard(不是搜索...)

https://vjudge.net/problem/LightOJ-1010 给定一个mn的棋盘&#xff0c;你想把棋子放在哪里。你必须找到棋盘上最多可以放置的骑士数量&#xff0c;这样就不会有两个骑士互相攻击。不熟悉棋手的注意&#xff0c;棋手可以在棋盘上攻击8个位置&#xff0c;如下图所示。 不论输入…