@toc二、命令列表2.2 class/classloader相关命令2.2.6 sm(查看已加载类的方法信息 )提示:“Search-Method” 的简写,这个命令能搜索出所有已经加载了 Class } } finally { lock.writeLock().unlock(); } }}举例1:显示类加载的方法基础语法 [arthas@18139]$举例2:显示类加载的executeTask方法详细信息基础语法:sm -d 全路径类名 方法名[arthas@18139]$ sm -d com.hero.lte.ems.sysmanager.cache.SMTaskCache .class文件,redefine到JVM里 )19.Arthas classloader (查看 classloader 的继承树,urls,类加载信息)20.Arthas sc(查看JVM已加载的类信息 )21.Arthas sm(查看已加载类的方法信息 )22.Arthas monitor(方法执行监控)23.Arthas stack (输出当前方法被调用的调用路径)24.Arthas trace
@toc二、命令列表2.2 class/classloader相关命令2.2.5 sc(查看JVM已加载的类信息 )提示:“Search-Class” 的简写,这个命令能搜索出所有已经加载到 JVM 中的 ,包括这个类所加载的原始文件来源、类的声明、加载的 ClassLoader 等详细信息。 [arthas@18139]$举例2:打印类的详细信息基础语法:sc -d 全路径类名[arthas@18139]$ sc -d com.hero.lte.ems.sysmanager.cache.SMTaskCache .class文件,redefine到JVM里 )19.Arthas classloader (查看 classloader 的继承树,urls,类加载信息)20.Arthas sc(查看JVM已加载的类信息 )21.Arthas sm(查看已加载类的方法信息 )22.Arthas monitor(方法执行监控)23.Arthas stack (输出当前方法被调用的调用路径)24.Arthas trace
我们已经将整个Class的构成讲述完了,不清楚的同学可以看一下关于Class文件的介绍,但是空有Class并没有什么用,在Class中的各种描述信息都需要被加载到虚拟机以后才能运行使用。 这就是虚拟机的类加载。 类加载概念 ? 上图是类加载和卸载的整个过程示意图,其中验证、准备、解析统称为连接阶段。 类加载-加载阶段 加载是类加载的第一个阶段,加载阶段的主要目标是: 通过一个类的全限定名来获取定义此类的二进制字节流 将字节流的静态信息结构转换为方法区(元数据区)的运行时数据结构 在内存中生成一个代表这个类的 非数组类的加载需要通过类加载器实现,既可以使用系统的提供的引导类加载,也可以使用用户自定义的类加载器去完成,关于类加载器后续我会单独写一篇文章来介绍,并且实现我们自己的一个类加载器。 本期类加载的加载阶段就介绍到这,下期我们会讲解类加载的连接阶段,我们下期再见!!!
三.类加载 1.动态加载和静态加载 基本说明 反射机制是 java 实现动态语言的关键,也就是通过反射实现类动态加载 1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强 2.动态加载:运行时加载需要的类 ,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性 3.举例说明 类加载时机 1.当创建对象时(new))2.当子类被加载时 3.调用类中的静态成员时 4.通过反射 Class.forName ("com.test.Cat"); 2.类加载流程图 类加载各阶段完成任务 3.类加载的五个阶段 3.1 加载阶段 JVM 在该阶段的主要目的是将字节码从不同的数据源(可能是 class 文件、 "B () 构造器被执行" //new B();//类加载 System.out.println(B.num);//100 如果直接使用类的静态属性,也会导致类的加载 10.getSuperClass:以 Class 形式返回父类信息 11.getInterfaces:以 Class[]形式返回接口信息 12.getAnnotations:以 Annotation[
文章目录 一、类加载器 二、类加载的双亲委托机制 一、类加载器 ---- Java 虚拟机 ClassLoader 类加载器 : Bootstrap ClassLoader : 启动类加载器 , 该 加载器由 ; 类加载的双亲委托机制 : 类加载器 ClassLoader 接收到 类加载任务 之后 , 自己不会先进行加载 , 反而将该 类加载任务 委托 给 父类类加载器 执行 ; 父类类加载器 接收 到 该 类加载任务 之后 , 也会 委托 父类的父类 类加载器 执行 ; 委托操作 , 会一直传递到 最顶层的 启动类加载器 Bootstrap ClassLoader ; 如果 启动类加载器 Bootstrap ClassLoader 完成了 类加载 操作 , 返回加载的类 ; 如果 启动类加载器 Bootstrap ClassLoader 无法完成 类加载 操作 , 就会 将 类加载任务 委托给 子类完成 ; 同理 , 父类 委托 给子类的 类加载任务 , 如果 子类类加载器 可以完成加载 , 成功返回 , 如果子类类加载器无法完成加载 , 就再次 将 类加载任务 委托给 子类的子类 , 继续向下传递 ;
,加载class的同时根据initialize是否初始化 2.连接 2.1.验证:确保被加载的类的正确性 验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求 元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。 加载机制 全盘负责,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入 双亲委托,先让父类加载器试图加载该类, ,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成加载请求(它管理的范围之中没有这个类)时,子加载器才会尝试着自己去加载 ? 自定义加载器 既然JVM已经提供了默认的类加载器,为什么还要定义自已的类加载器呢?
当类也就是class文件被加载到虚拟机内存开始,到卸载出内存为止。它将要执行以下7个步骤: 加载 验证 准备 解析 初始化 使用 卸载 ? 下面我们看一下每一个阶段的详细流程。 加载 加载也就是把class文件加载到虚拟机内存中。在加载时虚拟机需要完成3个方面的工作: 通过一个类的全限定名来获取类的二进制字节流。 将字节流所代表的静态存储结构转化为方法区中的运行时数据结构。 元数据验证:这个阶段主要验证的是字节码的描述信息是否符合Java语言规范,也就是说主要对类的元信息进行语法上的检查,保证符合Java语言规范的元信息。 字节码验证:这个阶段是最复杂的也是最耗时的验证,它主要目的是对类的方法体进行验证,校验类中的方法在运行时,不会做出威胁虚拟机的安全事件。 在解析时主要分为下面的几种: 类或接口的解析 字段解析 类方法解析 接口方法解析 初始化 初始化阶段主要的目的是为静态变量或者静态代码块执行赋值的操作。
类加载器种类 启动类加载器,Bootstrap ClassLoader,加载JACA_HOME\lib,或者被-Xbootclasspath参数限定的类 扩展类加载器,Extension ClassLoader ,加载\lib\ext,或者被java.ext.dirs系统变量指定的类 应用程序类加载器,Application ClassLoader,加载ClassPath中的类库 自定义类加载器,通过继承ClassLoader 实现,一般是加载我们的自定义类 双亲委派模型 类加载器 Java 类如同其它的 Java 类一样,也是要由类加载器来加载的;除了启动类加载器,每个类都有其父类加载器(父子关系由组合(不是继承)来实现); 所谓双亲委派是指每次收到类加载请求时,先将请求委派给父类加载器完成(所有加载请求最终会委派到顶层的Bootstrap ClassLoader加载器中),如果父类加载器无法完成这个加载(该加载器的搜索范围中没有找到对应的类 双亲委派好处 避免同一个类被多次加载; 每个加载器只能加载自己范围内的类; 类加载过程 类加载分为三个步骤:加载,连接,初始化; ?
类加载器会通过二进制流的方式获取到字节码文件的内容,接下来将获取到的数据交给Java虚拟机,虚拟机会在方法区和堆上生成对应的对象保存字节码信息(类加载器只参与加载过程中的字节码获取并加载到内存这一部分) 作为方法区这个类的各种数据的访问入口3.2 验证确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全(文件中的信息是否符合虚拟机规范有没有安全隐患)。 ,则按照自上而下的顺序依次执行3.6 使用JVM开始从入口方法执行用户的程序代码调用静态类成员信息(比如:静态字段、静态方法)使用new关键字为其创建对象实例3.7 小节1)当一个类被使用的时候,才会加载到内存 查看classloader的继承树,urls,类加载信息,使用classloader去getResource第1列为类加载名称,第2列为当前类加载器在内存中实例个数,第3列为当前类加载器加载了多少个类。 代码中,无法通过Java代码获取底层的虚拟机启动类加载器)在Arthas中可以通过sc -d 类名的方式查看加载这个类的类加载器详细的信息,如通过上图可以看到,java.lang.String类的类加载器是空的
类加载器子系统作用 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。 加载的类信息存放于一块称为方法区的内存空间。 除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射) 类加载器ClasLoader角色 class file存在于本地硬盘上 ,保证被加载类的正确性,不会危害虚拟机自身安全。 由于Java采用的是懒加载策略,只有当我们需要用到这个类的时候才会去加载他 初始化阶段就是执行类构造器方法<clinit>()的过程。
@toc二、命令列表2.2 class/classloader相关命令2.2.4 classloader (查看 classloader 的继承树,urls,类加载信息)提示查看 classloader 的继承树,urls,类加载信息。 举例1:按类加载类型查看统计信息基础语法:classloader [arthas@26938]$ classloader name .class文件,redefine到JVM里 )19.Arthas classloader (查看 classloader 的继承树,urls,类加载信息)20.Arthas sc(查看JVM已加载的类信息 )21.Arthas sm(查看已加载类的方法信息 )22.Arthas monitor(方法执行监控)23.Arthas stack (输出当前方法被调用的调用路径)24.Arthas trace
为什么要自定义加载器 原因: 1、存放在自定义路径上的类,需要通过自定义类加载器去加载。 【注意:AppClassLoader加载classpath下的类】 2、类不一定从文件中加载,也可能从网络中的流中加载,这就需要自定义加载器去实现加密解密。 方法来加载类,获取class对象。 一直提交给启动类加载器去加载,通过他加载,加载到的永远是/lib下面的java.lang.String 3、在这个自己写的类中写上main方法 public static void main(String 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
虽然java.lang.Class仅仅是一个镜像类,但是也保存了Test这个Java类中的全部信息,所以在JVM_GetClassDeclaredFields()函数中能够获取Test类中的全部字段。 Java类的字段、方法等全部信息。 (3)解析字段信息,parse_fields()。 (4)解析方法,parse_methods()。 该接口的第2个入参(入参从位置1开始计数)指明所调用的Java类对应的instance,第4个入参指明所调用的特定方法,第5个入参指明所调用的Java类的签名信息。 JavaCalls::call_virtual()接口的第6个入参则包含所调用的Java方法所需要的全部入参信息,在JVM加载Java应用程序主类时,向JavaCalls::call_virtual()
文章目录 一、类加载时机 1、隐式加载 2、显式加载 二、类加载步骤 一、类加载时机 ---- 1、隐式加载 类加载 的 隐式加载 , 没有明确的说明加载某个类 , 但是进行了如下操作 : 使用 new 关键字 直接 创建类的实例对象 ; 使用 new 关键字 直接 创建类的 子类 实例对象 ; 通过 反射方式 创建 类 / 子类 实例对象 ; 访问 类的 静态变量 , 对静态变量 进行 读 或者 写 操作 都会触发 隐式加载 ; 访问 类的 静态函数 ; 2、显式加载 显式加载 : 明确的说明要加载某个类 , 使用 Class.forName() 加载指定的类 ; 使用 ClassLoader.loadClass 加载指令的类 ; 二、类加载步骤 ---- 参考 【Java 虚拟机原理】Java 类加载过程 ( 加载 | 连接 - 验证 准备 解析 | 初始化 | 使用 | 卸载 ) 博客 ; 类加载步骤 : ① 装载 : 加载某个类时 , 首先要 查找 并 导入 Class 字节码文件 ; ② 链接 : 该阶段 , 可以分为以下 3 个子阶段 ; 验证 : 验证字节码文件是否正确 ; 准备 :
本节来学习类加载机制 什么是类加载 简单来说就是将.class文件实例成Class对象并进行初始化的过程,字节码必须通过类加载过程加载到JVM环境后才可以执行 classloder(类加载器)的使命就是将 .class文件加载到内存中,在启动之初进行类的Load、Link和Init,在加载类时使用的是双亲委派模型 类加载 类加载过程 1 加载阶段读取类文件产生的二进制流并转为特定的数据结构,创建对应的 类加载器 字节码文件加载到内存就是通过类加载器来实现的,类加载器类似于原始部落结构存在权力等级,最高的一层是家族中威望最高的Bootstrap,它是jvm启动时创建的,是通过C来实现的,并不存在于JVM 中 双亲委派模型 类加载器之间的这种层次关系就是双亲委派模型。 双亲委派模型要求除了顶层的启动类加载器外,其他的类加载器都应有自己的父类加载器 这部分内容是对第一张图中加载这个方框部分的内容的拓展
类加载器并不需要等到某个类被“首次主动使用”时再加载它,JVM 规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了 .class 文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误 /md/java/jvm/java-jvm-classload.html 2 类加载机制 2.1 双亲委派机制 双亲委派机制是指如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成 ,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器 在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。 既然是加载这个类时出现的问题,我们首先要知道是哪个类加载器在尝试加载这个类。 结合类加载机制中的全盘负责机制,我们知道这个匿名类是由加载依赖它的 org.apache.iotdb.MySum 的类加载器来加载的,我们把这个类加载器记为 A。
对象比较特殊,它虽然是对象,但是存放在方法区里面) 验证阶段 主要验证字节流的信息是否符合java虚拟机的规范验证魔数,版本等信息 准备阶段 主要为类变量(static修饰)分配内存空间,并设置初始值。 类加载器只用于实现类的加载动作。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。 从开发人员的角度类加载器有三种:启动类的加载器,扩展加载器,应用程序类加载器 启动类加载器:负责将存放在<JAVA_HOME>\lib目录中的类库加载到虚拟机内存中 扩展加载器:负责将存放在<JAVA_HOME >\lib\ext目录中的类库加载到虚拟机内存中 应用程序类加载器:它负责加载用户类路径(ClassPath)上所指定的类库 双亲委派机制 类加载器之间如下图的这种层次关系,称为类加载器的双亲委派模型。 双亲委派模型的工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中
类的生命周期 类加载过程 加载 验证 准备 解析 初始化 卸载 类的生命周期 一个类的完整生命周期如下: 类加载过程 Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚拟机是如何加载这些 一个非数组类的加载阶段(加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,这一步我们可以去完成还可以自定义类加载器去控制字节流的获取方式(重写一个类加载器的 loadClass() 方法)。 数组类型不通过类加载器创建,它由 Java 虚拟机直接创建。 类加载器、双亲委派模型也是非常重要的知识点,这部分内容会在后面的文章中单独介绍到。 该类没有在其他任何地方被引用 该类的类加载器的实例已被 GC 所以,在 JVM 生命周期内,由 jvm 自带的类加载器加载的类是不会被卸载的。但是由我们自定义的类加载器加载的类是可能被卸载的。 而我们自定义的类加载器的实例是可以被回收的,所以使用我们自定义加载器加载的类是可以被卸载掉的。 参考
类加载器基本概念 顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。 类加载器的代理模式 类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理给其父类加载器,由父类加载器先去尝试加载这个类,依次类推。 加载类的过程 在前面介绍类加载器的代理模式的时候,提到过类加载器会首先代理给其它类加载器来尝试加载某个类。这就意味着真正完成类的加载工作的类加载器和启动这个加载过程的类加载器,有可能不是同一个。 也就是说,哪个类加载器启动类的加载过程并不重要,重要的是最终定义这个类的加载器。两种类加载器的关联之处在于:一个类的定义加载器是它引用的其它类的初始加载器。 类加载器在成功加载某个类之后,会把得到的 java.lang.Class类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。
1.访问类的编译期静态常量时,不会触发类的初始化行为。类的初始化行为是指在类被加载之后(也就是类的Class对象被创建之后),为类的静态成员变量分配存储空间。 2.编译期静态常量会在编译阶段被存储到NonInitialization类的常量池中,在以后对编译期静态常量的引用都实际上被替换为对NonInitializaion类对自身常量池的引用,所以访问类的编译期静态常量并不会触发类的初始化行为 3.初始化一个类之前,会先初始化该类的父类。