浅谈JVM核心之JVM运行和类加载

前言

本篇博客将写一点关于JVM的东西,涉及JVM运行时数据区、类加载的过程、类加载器、ClassLoader、双亲委派机制、自定义类加载器等,这些都是博主自己的一点理解,如果有误,欢迎大家评论拍砖~

关于JVM运行时数据区

JVM运行时数据区

关于类加载

class文件加载至内存,链接(校验、解析),初始化;最终形成JVM可以直接使用的JAVA类型的过程。

加载:在方法区形成类的运行时数据结构;在堆里面形成该类的Class对象,作为访问方法区的入口。

加载

链接:class文件是否存在问题;一些符号引号替换成直接引用。

初始化:初始化一个类,先初始化它的父类。虚拟机会保证一个类的初始化在多线程环境中被正确加锁和同步。

要使用类A,必须先加载类A;加载类A,就会把静态变量、静态块合并初始化,然后在调用构造器。注意类的加载和初始化,只有一次。

关于类加载器

上文已经说了,类加载器的作用就是:将class文件的字节码内容加载到内存中,并将这些静态数据转化成方法区中的运行时数据结构,在堆中生成一个代表这个类的Class对象,作为方法区类数据的访问入口。

类加载器的层次结构

引导类加载器bootstrap classloader

加载JAVA核心库($JAVA_HOME/jre/lib/rt.jar),原生代码实现(C++),并不继承自java.lang.ClassLoader。

扩展类加载器extensions classloader

JAVA可以提供一个扩展目录($JAVA_HOME/jre/ext/*.jar)来加载Java类。

由sun.misc.Launcher.ExtClassLoader实现

应用程序类加载器application classloader(也称系统类加载器)

一般来说,JAVA应用的类由它加载,即加载路径是classpath下的路径。

由sun.misc.Launcher.AppClassLoader实现。

自定义类加载器

开发人员继承java.lang.ClassLoader实现自己的类加载器

类加载器的层次结构

关于java.lang.ClassLoader

ClassLoader的基本职责就是:

第一,根据指定的类名称,找到或者生成对应的字节码,并根据字节码生成class对象

第二,加载JAVA应用所需的资源,如配置文件等。

ClassLoader的组合模式

组合模式为双亲委派机制提供支持

demo:

类加载器的层次

引导类加载器是原生代码实现,我们获取不到,所以是null。

ClassLoader重要API

getParent():该类加载器的父类加载器

loadClass(String name):加载名称为name的类,并返回Class实例。

加载顺序是:先交给扩展类加载器加载,如果加载不到,交给引导类加载器加载,加载不到,交给自己去加载,如果自己也加载不到,那么ClassNotFoundException。【双亲委派机制】 如果要改变类的加载顺序,那么可以override该方法。

findClass(String name),不是加载,仅仅是查找而已

findLoadedClass(String name),查找已经被加载过的

defineClass(String name,byte[] b, int off ,int len),可以把字节数组的内容转换成JAVA类,并会返回Class实例。

类加载器的代理模式:双亲委派机制

类加载器的代理模式:就是把加载指定类的过程交给其他加载器。

JAVA默认使用的类加载器代理模式是:双亲委派机制。

双亲委派机制:

就是某个特定的类加载器接到加载类的请求时,首先将加载任务委托给父类加载器,依次追溯,比如说从应用加载器委托给扩展类加载器,从扩展类加载器委托给引导类加载器。这种委托,直至委托到层次最高的类加载器,即引导类加载器,如果委托的父类加载器可以完成加载任务,那么成功返回;只有父类加载器无法完成时,才去自己加载。

可以看出双亲委派机制的意思就是优先父类加载器加载!

试想如果我们定义了一个java.lang.String类,根据双亲委派机制,那么JDK只会加载它自己的String。这显然保证了Java核心库的类型安全。

双亲委派机制不是唯一的选择

虽然JDK默认的类加载机制是双亲委派机制,但是并不是所有都采用,比如有些服务器,如Tomcat,虽然也采用代理的方式加载,但是加载顺序却恰恰和双亲委派机制相反,它是首先尝试加载这个类,只有加载不到的情况下,才去让父类加载器代理加载。

为什么会这样呢,不是说双亲委派很安全么?

其实就是在安全,和灵活方面进行取舍!

写一个自定义类加载器

MyClassLoader:

自定义类加载器

重写findClass:

findClass

Test:

测试

一般情况下,自定义类加载器,需要继承自ClassLoader。

首先来说,可以检查请求的类是否已经被自定义的类加载器加载;如果加载了,那么直接返回;否则,那么交给父类加载器,就是进行双亲委派;如果双亲委派也加载不到,那么交给自定义类加载器进行“自定义的方式”来加载类。

另外,被2个不同的类加载加载的同一个类,JVM不会认为是一个类。

好了,关于JVM运行和类加载的过程就写到这里,^_^

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java JVM虚拟机运行机制

    一:JVM基础概念 JVM(Java虚拟机)一种用于计算设备的规范,可用不同的方式(软件或硬件)加以实现.编译虚拟机的指令集与编译微处理器的指令集非常类似.Java虚拟机包括一套字节码指令集.一组寄存器.一个栈.一个垃圾回收堆和一个存储方法域. Java虚拟机(JVM)是可运行Java代码的假想计算机.只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该系统上运行. 下面看下Jvm的体系结构图: 二:解释型语言和编译型语言的联系与区别. 编译型语言是通过

  • JVM类加载机制详解

    一.先看看编写出的代码的执行过程: 二.研究类加载机制的意义 从上图可以看出,类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比如热部署等,提高程序的灵活性和适应性. 三.类加载的一般过程 原理:双亲委托模式 1.寻找jre目录,寻找jvm.dll,并初始化JVM: 2.产生一个Bootstrap Loader(启动类加载器): 3.Bootstrap Loader自动加载E

  • 浅谈c++的编译和运行

    命令行编译: g++ xx.cpp 运行: ./a.out 以上这篇浅谈c++的编译和运行就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • 浅谈python3.6的tkinter运行问题

    python3.6在运行tkinter时要选择 run as Python unit-test, 否则报错 ModuleNotFoundError: No module named 'tkinter.ttk'; 'tkinter' is not a package 稍微提醒一下各位,仅此而已. 以上这篇浅谈python3.6的tkinter运行问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • 浅谈VUE项目打包后运行页面一片白问题

    目录 1.说明 2.问题说明 3.解决 3.1.index.js 3.2.utils.js 3.3.webpack.prod.conf.js 4.总结 1.说明 我们用VUE搭建一个脚手架后,在IDEA等工具中开发时,启动都没有什么问题,但是项目开发完成之后,可能需要部署上线,所以需要进行打包操作了,一般都是用下面命令进行打包: npm run build 打包过程一般没有什么问题,然后就会在工程目录下生成一个[dist]文件夹,里面就是我们打包好的文件,把这些文件部署到Nginx中或者Tomc

  • 浅谈JVM核心之JVM运行和类加载

    前言 本篇博客将写一点关于JVM的东西,涉及JVM运行时数据区.类加载的过程.类加载器.ClassLoader.双亲委派机制.自定义类加载器等,这些都是博主自己的一点理解,如果有误,欢迎大家评论拍砖~ 关于JVM运行时数据区 JVM运行时数据区 关于类加载 class文件加载至内存,链接(校验.解析),初始化:最终形成JVM可以直接使用的JAVA类型的过程. 加载:在方法区形成类的运行时数据结构:在堆里面形成该类的Class对象,作为访问方法区的入口. 加载 链接:class文件是否存在问题:一

  • 浅谈Laravel核心解读之Console内核

    Console内核 上一篇文章我们介绍了Laravel的HTTP内核,详细概述了网络请求从进入应用到应用处理完请求返回HTTP响应整个生命周期中HTTP内核是如何调动Laravel各个核心组件来完成任务的.除了处理HTTP请求一个健壮的应用经常还会需要执行计划任务.异步队列这些.Laravel为了能让应用满足这些场景设计了artisan工具,通过artisan工具定义各种命令来满足非HTTP请求的各种场景,artisan命令通过Laravel的Console内核来完成对应用核心组件的调度来完成任

  • 浅谈Jquery核心函数

    在Jquery中,所有的DOM对象都将封装成Jquery对象,而且只有Jquery对象才能使用Jquery方法或者属性来执行相应的操作. 所以Jquery提供了一个可以将DOM对象封装成Jquery对象的函数,就是Jquery核心函数jquery(),也称为工厂函数. jquery核心函数有7个重载,分别如下: jquery()  该函数返回一个空的jquery对象. jquery(elements)  该函数将一个或多个DOM元素转化为Jquery对象(或jquery集合) jquery(ca

  • 浅谈Java多进程程序的运行模式

    一般我们在java中运行其它类中的方法时,无论是静态调用,还是动态调用,都是在当前的进程中执行的,也就是说,只有一个java虚拟机实例在运行.而有的时候,我们需要通过java代码启动多个java子进程.这样做虽然占用了一些系统资源,但会使程序更加稳定,因为新启动的程序是在不同的虚拟机进程中运行的,如果有一个进程发生异常,并不影响其它的子进程. 在Java中我们可以使用两种方法来实现这种要求.最简单的方法就是通过Runtime中的exec方法执行java classname.如果执行成功,这个方法

  • 浅谈TypeScript 用 Webpack/ts-node 运行的配置记录

    公司项目代码是用 TypeScript 写的, 中间遇到有些代码不要放到 Node 里面去跑. 具体场景一些路由配置, 比较大的一块 JSON 数据定义在 TypeScript 里. 我另外有增加脚本, 基于这些 JSON 数据用来生成切换路由的函数. 这就需要运行 TypeScript 了, 而且可能包含一些额外的业务代码. 首先 Node 运行 TypeScript 有提供 ts-node 用来处理. ts-node 会先编译 TypeScript 代码到 JavaScript, 再调用 N

  • 浅谈Webpack核心模块tapable解析

    本文介绍了Webpack核心模块tapable,分享给大家,具体如下: 前言 Webpack 是一个现代 JavaScript 应用程序的静态模块打包器,是对前端项目实现自动化和优化必不可少的工具,Webpack 的 loader (加载器)和 plugin (插件)是由 Webpack 开发者和社区开发者共同贡献的,而目前又没有比较系统的开发文档,想写加载器和插件必须要懂 Webpack 的原理,即看懂 Webpack 的源码, tapable 则是 Webpack 依赖的核心库,可以说不懂

  • 浅谈jvm中的垃圾回收策略

    java和C#中的内存的分配和释放都是由虚拟机自动管理的,此前我已经介绍了CLR中GC的对象回收方式,是基于代的内存回收策略,其实在java中,JVM的对象回收策略也是基于分代的思想.这样做的目的就是为了提高垃圾 回收的性能,避免对堆中的所有对象进行检查时所带来的程序的响应的延迟,因为jvm执行GC时,会stop the word,即终止其它线程的运行,等回收完毕,才恢复其它线程的操作.基于分代的思想是:jvm在每一次执行垃圾收集器时,只是对一小部分内存 对象引用进行检查,这一小部分对象的生命周

随机推荐