关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

云南大王-JVM 虚拟机&&类加载(一)

发布时间:2020-04-13 00:00:00
虚拟机 虚拟机简介 Java 虚拟机(JVM)是运行java程序的抽象计算机,它是计算机设备的规范,可以采用不同方式进行实现,java 程序通过运行在JVM中实现跨平台,一次编译到处运行,不同的操作系统有不同的JDK版本,通过调用JNI方法去实现调用不同操作系统的方法 graph LR A[java源文件] B[class二进制字节码] C[JVM] D((Java native接口)) F[windows本地方法] H[linux本地方法] I[macOS本地方法] A-.编译.->B B-.加载.->C C-.打开文件.->D D-.windows-JDK.->F D-.linux-JDK.->H D-.macOS-JDK.->I Java虚拟机不和包括java的语言绑定,它只和Class文件这种特定的二进制文件格式绑定,class文件中包含了虚拟机指令集和符号表以及若干其他辅信息。 graph LR A[java程序] B[JRuby程序] C[Groovy程序] D[java编译器] E[JRuby编译器] F[Groovy编译器] H[字节码] I[Java虚拟机] A-.*.java文件.->D B-.*.rb文件.->E C-.*.groovy文件.->F D-->H E-->H F-->H H-.*.class文件.->I 虚拟机产品 Sun HotSpot(JVM) BEA JRocket IBM J9 Microsoft JVM Google Android Dalvik Class 文件 Class文件是以8位字节基础单位的二进制流,各项数据严格按照顺序排列在class文件中,中间没有任何分隔符,如果超过8位,是按照高位在前的方式存储的。 Class文件的组成 java虚拟机指令集 符号表 其他辅助信息 常量池 java代码在编译后,Class文件并表不会保存各个方法,字段在内存里面的最终布局,因为在编译期间并不知道引用类的实际地址,因此只能使用符号描述来代替,当虚拟机真正的运行的时候,需要从class文件的常量池获得对应的符号引用,然后在类的创建或者运行时解析称具体的内存地址 也就是说在类被加载的时候,一定是在内存中分配了具体的地址,这样在解析的时候就可以替换符号引用成真正的地址。 Class文件的常量池主要存放2大类型: 字面量 字面量是接近java语言层面的常量概念,如文本字符串,声明final的常量值等 符号引用 主要包括类和接口的全称限定名,字段的名称和描述符,方法的名称和描述符 虚拟机类加载 类加载到JVM中生命空间 graph LR A[加载Loading] B[验证Verification] C[准备Preparation] D[解析Resolution] E[初始化Initialization] F[使用Using] G[卸载Unloading] A-->B D-->E E-->F F-->G subgraph 连接 B-->C C-->D end 加载 加载的过程做的事情是: 获取二进制字节流 静态存储结构转化为方法区的运行时结数据结构 在java堆对象里面生成一个类对象,作为方法区的入口 Java中获取二进制字节流的途径有 从Zip,Jar,War等格式文件中获取 从网络中获取 Applet应用 运行时计算生成,动态代理技术 JSP应用生成对应的Class类 验证 验证是连接的第一步,要确保Class文件中的字节流包含的信息符合JVM的要求,验证阶段大体分为如下几个阶段 文件格式验证 验证文件标识是否正确,版本号是否能匹配当前JVM,常量池中的常量是否有不支持的类型等 。经过这个阶段的验证后,字节流才会进入的方法区中进行存储,后面的验证只是基于方法区的存储结构验证,不会在验证字节流 元数据验证 主要是对字节码描述的语义进行分析,保证符号java语言的规范,类的继承,抽象类的实现等等 字节码验证 符号引用验证 该阶段发生在符号引用替换成直接引用时,验证符号引用的匹配校验等等 准备 准备阶段是为了给类分配内存并设置类变量的初始化Clint,这些变量使用的内存,都在方法区中进行分配,只是对类变量进行内存分配(Static 修饰的)不包括实例变量,实例变量是随着类实例化后一起在堆中分配的 :类的初始化 父静态变量 父类静态块 子类静态变量 子类的静态块 : 对象的初始化 父类的变量初始化,父类的构造函数。。。。。。 解析 解析的目的是将常量池中的符号引用替换为直接引用 字段的解析 class A extends B implements C{ private String str; //字段的解析 } graph TB A{A是否能匹配} B{B是否能匹配} C{C是否能匹配} A-->|是|E[结束] A-->|否|C subgraph 接口 C-->|是|F(结束) end subgraph 父类 C-->|否|B B-->|是|I(结束) B-->|否|J((抛出异常)) end 类方法解析 先查找本类 然后父类中递归查找 在类实现的接口列表及它们的父接口 接口方法解析 先查找本接口 在接口的父接口中递归查找 类加载器 通过类的全限定名来获取描述类的二进制字节流,把类加载这个阶段中的动作放到虚拟机外部去实现,以便应用程序能够自己决定如果去获取自己需要的类,实现这个动作加做类加载器。 Java中有abstract class ClassLoader 类。 ClassLoader.loadClass类的核心总结是: 同一个时间只能允许一个线程去加载类 在加载类之前会检查下是否已经加载过,只有没有被加载的才能去被加载 能父加载器加载的绝不会交给子加载器去加载,为什么要这样,是为了保证安全,比如你自己写个相同名字的java底层类比如java.util.ArrayList通过子加载器到内存中,那不是乱套了么,到时候植入个病毒代码,用的人 不GG了 父加载器加载不到的才会交给子加载器加载 加载器类型 从JVM的角度去看 只存在2中类加载器,一种是启动类加载器(Bootstrap ClassLoader)是由C++语言实现的。还有一种是另外的类加载器,是由java语言实现的,独立于JVM,全部是继承了java.lang.ClassLoader 如果从我们开发角度去看,分为3中类加载器: Bootstrap ClassLoader启动类加载器,负责Java_Home/lib 下面的类库加载到内存中,由于这边涉及到虚拟机本地的实现细节,所有我们开发者无法获取到类加载器的引用。 Extension ClassLoader 扩展类加载器 负责加载Java_Home/lib/ext或者由系统变量java.ext.dirs指定位置的类加载到内存中 //Launcher.class文件中 static class ExtClassLoader extends URLClassLoader { private static volatile Launcher.ExtClassLoader instance; public static Launcher.ExtClassLoader getExtClassLoader() throws IOException { if (instance == null) { Class var0 = Launcher.ExtClassLoader.class; synchronized(Launcher.ExtClassLoader.class) { if (instance == null) { instance = createExtClassLoader(); } } } return instance; } .... } Application ClassLoader 应用程序类鸡加载器,它负责系统路径ClassPath中指定的类库加载到内存中,这个类加载器是 ClassLoader类中的getSystemClassLoader静态方法的返回值 //java/lang/ClassLoader.java 文件中 public static ClassLoader getSystemClassLoader() { initSystemClassLoader(); if (scl == null) { return null; } SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkClassLoaderPermission(scl, Reflection.getCallerClass()); } return scl; } graph BT A[Bootstrap加载器] B[ExtClassLoader] C[AppClassLoader] D[UseClassLoader1] F[UseClassLoader2] B --> A subgraph 非JVM C --> B D --> C F --> C end 有兴趣的可以自己执行看下 String appClassLoaderPath = System.getProperty("java.class.path"); System.out.println(appClassLoaderPath); String extClassLoaderPath = System.getProperty("java.ext.dirs"); System.out.println(extClassLoaderPath); String bootClassLoaderPath = System.getProperty("sun.boot.class.path"); System.out.println(bootClassLoaderPath); 双亲委派 什么是双亲委派 如果一个类加载器收到了某个类的加载请求,则该加载器不会加载,而是把这个请求抛给父类加载器,因此所有的类加载请求都会到达顶端的类加载器 只有当父类加载器在其范围内没法找到所需要类,才会把结果反馈给子加载器,子加载器在尝试自己加载 如何打断 自己写个类加载器 并重写loadClass方法 就可以了! 为什么要使用双亲委派 对任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。判断两个类是否"相等",必须是在这两个类被同一个类加载器加载的前提下。 基于双亲委派模型设计,那么Java中基础类,如Object类重复多次的问题就不会存在了,因为经过层层传递,加载请求最终都会被BootstrapClassLoader所响应。加载的Object类也会只有一个,否则如果用户自己编写了一个java.lang.Object类,并把它放到了ClassPath中,会出现很多个Object类,这样Java类型体系中最最基础的行为都无法保证,应用程序也将一片混乱。

相关阅读

centos7系统中忘记了root管理员账号密码的解决方式公司管理必须的20条军规[参考]云南昆明天猫旗舰店如何开_怎么开_要什么条件云南大王-通俗理解spring源码(三)—— 获取xml的验证模式 云南大王-用户登录 云南大王-【Golang进阶】指针的详细讲解 云南大王-Java 单线程代码ThreadLocal串值问题 云南大王-Java 实例级别的锁和类级别的锁 云南大王-工作流引擎会签,加签,主持人,组长模式专题讲解 云南大王-Android连载5云南大王-NTP对时器(NTP对时服务器)重要性!京准电子科技 云南大王-关于redis单线程的分析 云南大王-CVE云南大王-PHP SESSION反序列化本地样例分析 云南大王-这不就是多线程ThreadPoolExecutor和阻塞队列吗 云南大王-Tomcat AJP 文件包含漏洞(CVE云南大王-讲真,这两款idea插件,能治愈你英语不好的病 云南大王-消息中间件ActiveMQ、RabbitMQ、RocketMQ、ZeroMQ、Kafka如何选型? 云南大王-JVM系列十三(类加载器). 云南大王-Win10安装MySQL8压缩包版 云南大王-初始WebApi(2) 云南大王-初识人工智能(二):机器学习(一):sklearn特征抽取 云南大王-Popup中ListBox的SelectChange事件关闭弹出窗体后主窗体点击无效BUG 云南大王-基础知识记录 云南大王-FastDFS搭建图片服务器 云南大王-git/sourcetree解决本地仓库历史合并到线上仓的历史数据合并问题_refusing to merge unrelated histories 云南大王-js判断字符是否在数组中【转】 云南大王-Python 云南大王-面向对象之多线程(可捎带电梯调度) 云南大王-Python练习题2.5求奇数分之一序列前N项和(存在问题) 云南大王-React 中的前端路由 react云南大王-VSCODE 远程开发树莓派 云南大王-React新闻网站云南大王-vs .net CS0006 C# 未能找到元数据文件 .dll 云南大王-Vue.js 技术揭秘 云南大王-流程控制语句云南大王-Python学习笔记:Python的时间操作(time,datetime,timedelta,calendar) 云南大王-流程控制语句云南大王-golang Gin framework with websocket 云南大王-多重判断if..else嵌套语句 云南大王-用户登录 云南大王-流程控制语句云南大王-密码类 云南大王-Unity2018发布WebGL注意事项总结 云南大王-web系统安全运营之基础云南大王- 流程控制语句云南大王-中型WPF客户端开发项目总结(3.3.4) 云南大王-流程控制语句云南大王-流程控制语句云南大王-流程控制语句云南大王-中型WPF客户端开发项目总结(4) 云南大王-流程控制语句云南大王-ASP.NET Core笔记(4) 云南大王-C# 基础知识系列云南大王-让 .NET 轻松构建中间件模式代码(二) 云南大王-基于 HTML5 WebGL 的 水泥工厂可视化系统 云南大王-.NET Core 3 WPF MVVM框架 Prism系列之导航系统 云南大王-《JavaScript异步编程》精读笔记 云南大王-合理使用CSS框架,加速UI设计进程 云南大王-CLSID 为 {000209FF云南大王-从零基础转行到前端大牛,需要经过哪几个阶段? 云南大王-一个简单的例子看明白 async await Task 云南大王-【目前】宇宙第一IDE Visual Studio 合并压缩css、js扩展组件云南大王-写一个通用的List集合导出excel的通用方法 云南大王-Bootstrap4 按钮组+徽章(Badges)+进度条+分页+列表组 云南大王-Web前端工程师需要学些什么? 云南大王-react嵌套路由 云南大王-【java框架】Struts2(2) 云南大王-javaSE笔记云南大王-.net core 集成 sentry 进行异常报警 云南大王-Java の 四种引用 云南大王-JVM 虚拟机&&类加载(一) 云南大王-使用Fastjson实现JSON与JavaBean之间互相转换 云南大王-Python操作Oracle数据库:cx_Oracle 云南大王-为什么要用内插字符串代替string.format 云南大王-作为字节跳动的面试官,有些话我不得不说! 云南大王-微信公众号自定义菜单与启用服务器配置冲突(图文消息、链接及文本回复) 云南大王-C#队列学习笔记:RabbitMQ延迟队列 云南大王-Disruptor 基础篇 云南大王-C#获取设备(Audio和Video)名称 简单整理 云南大王-基于注解的IOC配置 云南大王-C#调用EnumDevice获取设备信息 云南大王-Jenkins基础系统之更换镜像源 云南大王-Jenkins基础系统之完整的.net项目编译 云南大王-Scala学习系列(二)——环境安装配置 云南大王-WinForm中DataGridView复制选中单元格内容解决方案 云南大王-关键词匹配优化(第0篇)—— 问题和思路 云南大王-ASP.NET CORE WEBAPI文件下载 云南大王-GC垃圾回收器 云南大王-多线程之旅(Task 任务) 云南大王-当模板方法遇到了委托函数,你的代码又可以精简了 云南大王-基于.NetCore3.1搭建项目系列 —— 使用Swagger导出文档 (补充篇) 云南大王-关键词匹配优化(第1篇)—— 测试计算过程 云南大王-原理解密 → Spring AOP 实现动态数据源(读写分离),底层原理是什么 云南大王-Navicat 密码加密算法 云南大王-【WPF学习】第六十六章 支持可视化状态 云南大王-composer安装 windows 云南大王-ASP.NET Core中的Controller 云南大王-HttpClient来自官方的JSON扩展方法 云南大王-Python3标准库:http.cookies HTTP cookie
/template/Home/Zkeys/PC/Static