JVM加载class文件的原理机制实例详解

目录
  • 一、JVM简介
  • 二、JVM的组成部分
  • 三、JVM加载class文件的原理机制

一、JVM简介

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

Java语言的一个非常重要的特点就是与平台的 无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改的运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的及其指令执行。这就是Java能够“一次编译,到处运行”的原因。

二、JVM的组成部分

由图可以看出,JVM是运行在操作系统之上的,它与硬件没有直接的交互。

1. 类加载器 Class Loader

类加载器的作用是加载类文件到内存,比如编写一个HelloWorld.java程序,然后通过javac编译生成class文件。由Class Loader将class文件加载到内存中。但是Class Loader加载class文件有格式要求。
注意:Class Loader只管加载,只要符合文件结构就加载,至于能不能运行,是由Execution Engine负责。
2. 执行引擎 Exexution Engine
执行引擎也叫作解释器,负责解释命令,提交操作系统执行。
3. 本地接口 Native Interface
本地接口的作用是为了融合不同的编程语言为Java所用。它的初衷是为了融合C/C++程序,Java诞生的时候是C/C++横行的时候,要想立足,必须要有一个聪明的、睿智的调用C/C++程序,于是就在内存中专门开辟了一块区域处理标记为native的代码,它的具体做法是Native Method Stack中登记native方法,在Execution Engine执行时加载加载native libraries。目前该方法只有在与硬件有关的应用中才会使用,在企业级应用中已经比较少见,因为现在的异构领域间的通信很发达,比如可以使用Socket通信,也可以使用WebService等。
4. 运行数据区 Runtime data area
运行数据区使整个JVM的重点。我们所写的程序都被加载到这里,之后才开始运行,Java生态系统如此的繁荣,得益于该区域的优良自治。

三、JVM加载class文件的原理机制

1. Java中的所有类,必须被装载到JVM中才能运行,这个装载工作是由JVM中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中,作用就是在运行时加载类。
Java类加载器基于三个机制:委托、可见性和单一性。
(1)委托机制是指加载一个类的请求交给父类加载器,如果这个父类加载器不能够找到或加载这个类,那么再加载它。
(2)可见性的原理是子类的加载器可以看见所有的父类加载器加载的类,而父类加载器看不到子类加载器加载的类。
(3)单一性原理是指一个类仅被加载一次,这是由委托机制确保子类加载器不会再次加载父类加载器加载过的类。
2. Java中的类大致分为三种:
(1)系统类
(2)扩展类
(3)由程序员自定义的类
3. 类装载有两种方式
(1)隐式装载:
程序在运行过程中当碰到通过new等方式生成类或者子类对象、使用类或者子类的静态域时,隐式调用类加载器加载对应的的类到JVM中。
(2)显式装载:
通过调用Class.forName()或者ClassLoader.loadClass(className)等方法,显式加载需要的类。
4. 类加载的动态性体现
一个应用程序总是由n多个类组成,Java程序启动时,并不是一次把所有的类全部加载再运行,他总是把保证程序运行的基础类一次性加载到JVM中,其他类等到JVM用到的时候再加载,这样是为了节省内存的开销,因为Java最早就是为嵌入式系统而设计的,内存宝贵,而用到时再加载这也是Java动态性的一种体现。
5. Java类加载器
Java中的类加载器实质上也是也是类,功能是把类加载入JVM中,值得注意的是JVM的类加载器有三个,原因有:一方面是为了分工明确,各自负责各自的区块,另一方面为了实现委托模型。
层次结构如下:
BootStrap Loader(引导类加载器) ----- 负责加载系统类

ExtClassLoader(扩展类加载器) ----- 负责加载扩展类
AppClassLoade(应用类加载器)r ----- 负责加载应用类
6. 类加载器之间如何协调工作的
Java中有三个类加载器,碰到一个类需要加载时,Java采用委托模型机制来协调和区分该由哪个类加载器完成。简单来说就是,“类装载器有载入类的需求时,会先请示其Parent使用其搜索路径帮忙载入”,如果Parent找不到,那么才由自己依照自己的搜索路径搜索类。
实例一:

package ClassLoaderTest;
public class ClassLoaderTest {
    public static void main(String[] args) {
        ClassLoader c1 = ClassLoaderTest.class.getClassLoader();
        System.out.println(c1);
        ClassLoader c1Parent = c1.getParent();
        System.out.println(c1Parent);
        ClassLoader c1Root = c1Parent.getParent();
        System.out.println(c1Root);
    }
}

执行结果:

可以看出ClassLoaderTest是由AppClassLoader加载器加载的。AppClassLoader的Parent加载器是ExtClassLoader。但是ExtClassLoader的Parent是null,在Java中是无法获取的。
实例二:

public class Test2 {
    public void test(){
        System.out.println(Test2.class);
        System.out.println(this.getClass());
        System.out.println(Test2.class.getClassLoader());
    }
}
public class Test1 {
    public static void main(String[] args) {
        System.out.println(Test1.class.getClassLoader());
        Test2 test2 = new Test2();
        test2.test();
    }
}

执行结果:

7. 预先加载和依需求加载
Java运行环境为了优化系统,提高程序的执行速度,在JRE运行的开始会将Java运行所需要的基本类采用预先加载(pre-loading)的方法全部加载到内存当中,因为这些单元在Java程序运行的过程当中要经常使用的,主要包括JRE的rt.jar文件里面所有的.class文件。
当java.exe虚拟机开始运行以后,它会找到安装在机器上的JRE环境,然后把控制权交给JRE,JRE的类加载器会自动将lib目录下的rt.jar基础类别文件库加载进内存,这些文件是Java程序执行所必需的,所以系统在开始就将这些文件加载,避免以后的多次IO操作,从而提高程序执行效率。然而我们在程序中需要使用自定义的类的时候就要使用依需求加载(load-on-demand)的方式,就是在Java程序需要用到的时候再加载,以减少内存的消耗。
8. ClassLoader中一些 重要的方法

9.什么地方适用类加载器
最经典的例子就是AppletClassLoader,他被用来加载Applet使用的类,而Applet大部分是在网上使用,而非本地的操作系统使用。使用不同的类加载器,你可以从不同的源地址加载同一个类,它们被视为不同的类。J2EE使用多个类加载器加载不同地方的类,例如War文件由Web-app类加载器加载,而EJB-JAR中的类由另外的类加载器加载。有些服务器也支持热部署,这是由类加载器实现。你也可以使用类加载器来加载数据库或者其他持久层的数据。
10. 类加载器的阶层体系
Java类加载器的工作原理:
当执行Java的.class文件的时候,java.exe会帮助我们找到jRE,接着找到JRE内部的jcm.dll,这才是真正的Java虚拟机器,最后加载动态库,激活Java虚拟机器。虚拟机激活以后,会先做一些初始化的动作,比如说读取系统参数等。一旦初始化动作完成后,就会产生第一个类加载器-----Bootstrap Loader,Bootstrap Loader是由C++撰写而成,这个Bootstrap所做的初始工作中,除了一些基本的初始化动作之外,最重要的就是加载Launcher.java之中的ExtClassLoader,并设定其parent为null,代表其父加载器为BootstrapLoader。然后Bootstrap loader再要求加载Launcher.java之中的AppClassLoader,并设定其parent为之前产生的ExtClassLoader实体。这两个类加载器都是以静态类的形式存在的。注意:Launcher E x t C l a s s L o a d e r . c l a s s 与 L a u n c h e r ExtClassLoader.class与Launcher ExtClassLoader.class与LauncherAppClassLoader.class都是由Bootstrap Loader所加载,所以Parent和由哪个类加载器加载没有关系。
三者之间的关系:
Bootstrap Loader <—(extends)-----ExtClassLoader <—(extends)—AppClassLoader
这三个类加载器构成了Java的类加载体系。它们分别从以下的路径寻找程序所需要的类:
Bootstrap Loader:sun.boot.class.path
ExtClassLoader:java.ext.dirs
AppClassLoader:java.class.path
这三个参数可以通过System.getProperty()函数得到具体对应的路径。

到此这篇关于JVM加载class文件的原理机制的文章就介绍到这了,更多相关JVM加载class文件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JVM中ClassLoader类加载器的深入理解

    JVM的体系结构图 先来看一下JVM的体系结构,如下图: JVM的位置 JVM的位置,如下图: JVM是运行在操作系统之上的,与硬件没有直接的交互,但是可以调用底层的硬件,用JIN(Java本地接口调用底层硬件) JVM结构图中的class files文件 class files文件,是保存在我们电脑本地的字节码文件,.java文件经过编译之后,就会生成一个.class文件,这个文件就是class files所对应的字节码文件,如下图: JVM结构图中的类加载器ClassLoader的解释 类加

  • jvm之java类加载机制和类加载器(ClassLoader)的用法

    当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化. 一.类加载过程 1.加载 加载指的是将类的class文件读入到内存,并为之创建一个java.lang.Class对象,也就是说,当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象. 类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础

  • 浅谈JVM之java class文件的密码本

    简介 机器可以读,人为什么不能读?只要我们掌握java class文件的密码表,我们可以把二进制转成十六进制,将十六进制和我们的密码表进行对比,就可以轻松的解密了. 下面,让我们开始这个激动人心的过程吧. 一个简单的class 为了深入理解java class的含义,我们首先需要定义一个class类: public class JavaClassUsage { private int age=18; public void inc(int number){ this.age=this.age+

  • JVM加载class文件的原理机制实例详解

    目录 一.JVM简介 二.JVM的组成部分 三.JVM加载class文件的原理机制 一.JVM简介 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的. Java语言的一个非常重要的特点就是与平台的 无关性.而使用Java虚拟机是实现这一特点的关键.一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码.而引入Java语言虚拟机后,Java语言在不同

  • IOS中Weex 加载 .xcassets 中的图片资源的实例详解

    IOS中Weex 加载 .xcassets 中的图片资源的实例详解 前言: 因为 .xcassets 中的图片资源只能通过 imageNamed: 方法加载,所以需要做一些特殊处理,才能提供给 Weex 使用(PS:纯属娱乐,因为 Weex 跨平台的特性,这种针对某一端做实现的方案实用价值并不大). 方案 观察 WeexSDK 发现有 WXImgLoaderProtocol 这个协议,这个协议包含了下面的方法: - (id<WXImageOperationProtocol>)downloadI

  • 微信小程序 图片加载(本地,网路)实例详解

    在微信小程序中,要显示一张图片,有两种图片加载方式: 加载本地图片 加载网络图片 加载本地图片 <image class="widget__arrow" src="/image/arrowright.png" mode="aspectFill"> </image> src="/image/arrowright.png" 这句就是加载本地图片资源的.想想iOS中的加载本地图片,imageName:,类似.

  • 加载 vue 远程代码的组件实例详解

    在我们的 vue 项目中(特别是后台系统),总会出现一些需要多业务线共同开发同一个项目的场景,如果各业务团队向框架中提供一些私有的展示组件,但是这些组件并不能和框架一起打包,因为框架不能因为某个私有模块的频繁变更而重复构建发布.在这种场景下我们需要一个加载远程异步代码的组件来完成将这些组件加载到框架中. vue-cli 作为 Vue 官方推荐的项目构建脚手架,它提供了开发过程中常用的,热重载,构建,调试,单元测试,代码检测等功能.我们本次的异步远端组件将基于 vue-cli 开发. 需求分析 如

  • Java异或技操作给任意的文件加密原理及使用详解

    异或简单介绍:异或是一种基于二进制的位运算,用符号XOR或者 ^ 表示,其运算法则是对运算符两侧数的每一个二进制位,同值取0,异值取1. 简单理解就是不进位加法,如1+1=0,,0+0=0,1+0=1. 需求描述 在信息化时代对数据进行加密是一个很重要的主题,在做项目的过程中,我也实现了一个比较复杂的加密算法,但是由于涉及到的技术是保密的,所以在这里我实现一个比较简单的版本,利用文件的输入输出流和异或操作进行任意文件的加密,关于解密算法,很简单,自己思考下就能解决. 数学原理 该加密算法利用的是

  • Vue首评加载速度及白屏时间优化详解

    目录 项目背景 splitChunks CDN GZIP 删除文件预加载 项目背景 测试环境的管理后台应客户需求最近加了点东西,加载的东西变多,使得整个项目变得有点臃肿了,首屏以及刷新后渲染速度变得极其缓慢.之前10s左右还能勉强接受,这次一下干到30s,整个人都崩溃了,花了点时间优化了一下. 环境:vue:2.6.11,vue-cli:3.0 splitChunks 看到上面图片里的文件其实并不大,最大的也就287k. 这也是优化过的,之前都是有的最大为1m左右,在vue.config.js配

  • Kotlin对象的懒加载方式by lazy 与 lateinit 异同详解

    目录 前言 lateinit by lazy 总结 前言 属性或对象的延时加载是我们相当常用的,一般我们都是使用 lateinit 和 by lazy 来实现. 他们两者都是延时初始化,那么在使用时那么他们两者有什么区别呢? lateinit 见名知意,延时初始化的标记.lateinit var可以让我们声明一个变量并且不用马上初始化,在我们需要的时候进行手动初始化即可. 如果我们不初始化会怎样? private lateinit var name: String findViewById<Bu

  • SpringBoot Starter依赖原理与实例详解

    目录 1 Starter 2 了解 spring.factories机制 2.1 不同包路径下的依赖注入 2.2 spring.factories 机制 3 spring.factories 机制的实现源码分析 4 程序运行入口run() 1 Starter 在开发 SpringBoot 项目的时候,我们常常通过 Maven 导入自动各种依赖,其中很多依赖都是以 xxx-starter 命名的. 像这种 starter 依赖是怎么工作的呢? 2 了解 spring.factories机制 导入一

  • Apache Cordova Android原理应用实例详解

    目录 前言 技术选型 技术原理 1. 如何本地加载url对应的资源 2. webview如何使用js调用app原生api 3. app原生api如何回调webview中的js 4. 多个plugin的情况 关于踩到的坑 1. 打包路径配置问题 2. success不回调问题 前言 从原理到应用复盘一下自己做过的所有项目,希望能让我自己过两年仍然能看懂现在写的代码哈哈.在项目里我只负责了Android的开发包括插件开发和集成,ios没摸到,有机会也得自己玩下,但是这篇文章不会接触. 技术选型 现在

  • Java的SPI机制实例详解

    Java的SPI机制实例详解 SPI的全名为Service Provider Interface.普通开发人员可能不熟悉,因为这个是针对厂商或者插件的.在java.util.ServiceLoader的文档里有比较详细的介绍.究其思想,其实是和"Callback"差不多."Callback"的思想是在我们调用API的时候,我们可以自己写一段逻辑代码,传入到API里面,API内部在合适的时候会调用它,从而实现某种程度的"定制". 典型的是Colle

随机推荐