java面试题jvm字节码的加载与卸载

虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换分析和初始化,最终形成可以被虚拟节直接使用的JAVA类型,这就是虚拟机的类加载机制。

类从被加载到虚拟机内存到卸载出内存的生命周期包括:加载->连接(验证->准备->解析)->初始化->使用->卸载

初始化的5种情况:

1.使用new关键字实例化对象时,读取或设置一个类的静态字段,除被final修饰经编译结果放在常量池的静态字段,调用类的静态方法时。 2.使用java.lang.reflect包方法对类进行反射调用时。(Class.forName())。 3.初始化子类时,如果父类没有初始化。 4.虚拟机启动时main方法所在的类。 5.当使用JDK1.7动态语言支持时,java.lang.invoke.MethodHandle实例解析结果为REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄,且对应类没有进行初始化。

加载 加载是类加载的第一个阶段,虚拟机要完成以下三个过程:

1.通过类的全限定名获取定义此类的二进制字节流。 2.将字节流的存储结构转化为方法区的运行时结构。 3.在内存中生成一个代表该类的Class对象,作为方法区各种数据的访问入口。

验证 目的是确保class文件字节流信息符合虚拟机的要求。

准备 为static修饰的变量赋初值,例如int型默认为0,boolean默认为false。

解析 虚拟机将常量池内的符号引用替换成直接引用。

初始化 初始化是类加载的最后一个阶段,将执行类构造器< init>()方法,注意这里的方法不是构造方法。该方法将会显式调用父类构造器,接下来按照java语句顺序为类变量和静态语句块赋值。

方法调用

Java是一门面向对象的语言,它具有多态性。那么虚拟机又是如何知道运行时该调用哪一个方法?

静态分派是在编译期就决定了该调用哪一个方法而不是由虚拟机来确定,方法重载就是典型的静态分派。 动态分派是在虚拟机运行阶段才能决定调用哪一个方法,方法重写就是典型的动态分派。

动态分派的实现:当调用一个对象的方法时,会将该对象的引用压栈到操作数栈,然后字节码指令invokevirtual会去寻找该引用实际类型。如果在实际类型中找对应的方法,且访问权限足够,则直接返回该方法引用,否则会依照继承关系对父类进行查找。实际上,如果子类没有重写父类方法,则子类方法的引用会直接指向父类方法。

由Java虚拟机自带的类加载器所加载的类,在虚拟机的生命周期中,始终不会被卸载。

  前面介绍过,Java虚拟机自带的类加载器包括根类加载器扩展类加载器系统类加载器

  Java虚拟机本身会始终引用这些类加载器,而这些类加载器则会始终引用它们所加载的类的Class对象,因此这些Class对象始终是可触及的

  由用户自定义的类加载器加载的类是可以被卸载的。

具体的例子为:

loader1变量和obj变量间接应用代表Sample类的Class对象,而objClass变量则直接引用它。

  如果程序运行过程中,将上图左侧三个引用变量都置为null,此时Sample对象结束生命周期,MyClassLoader对象结束生命周期,代表Sample类的Class对象也结束生命周期,Sample类在方法区内的二进制数据被卸载

  当再次有需要时,会检查Sample类的Class对象是否存在,如果存在会直接使用,不再重新加载;如果不存在Sample类会被重新加载,在Java虚拟机的堆区会生成一个新的代表Sample类的Class实例(可以通过哈希码查看是否是同一个实例)。

时间: 2025-01-10 02:05:16

java面试题jvm字节码的加载与卸载的相关文章

JVM --字节码的加载

ClassLoader类加载器 常见的类加载器有BootStrapClassLoader<-ExtClassLoader<-AppClassLoader<-用户ClassLoader BootStrapClassLoader:加载Java自带的核心类: ExtClassLoader加载在/jre/lib/ext目录下的jar包,同样用户可以将jar放在该目录下. AppClassLoader 加载classpath下面的内容, 加载过程: 读取文件并加载,首先申请父类的加载器进行加载,如

JVM总结(五):JVM字节码执行引擎

JVM字节码执行引擎 运行时栈帧结构 局部变量表 操作数栈 动态连接 方法返回地址 附加信息 方法调用 解析 分派 –“重载”和“重写”的实现 静态分派 动态分派 单分派和多分派 JVM动态分派的实现 基于栈的字节码解释执行引擎 基于栈的指令集与基于寄存器的指令集 JVM字节码执行引擎 虚拟机是相对于“物理机”而言的,这两种机器都有代码执行能力,其区别主要是物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上的,而虚拟机的执行引擎是自己实现的.因此程序员可以自行制定指令集和执行引擎的

JVM字节码增强

JVM——字节码增强技术简介 Java字节码增强指的是在Java字节码生成之后,对其进行修改,增强其功能,这种方式相当于对应用程序的二进制文件进行修改.Java字节码增强主要是为了减少冗余代码,提高性能等. 实现字节码增强的主要步骤为: 1.修改字节码 在内存中获取到原来的字节码,然后通过一些工具(如 ASM,Javaasist)来修改它的byte[]数组,得到一个新的byte数组. 2.使修改后的字节码生效 有两种方法: 1) 自定义ClassLoader来加载修改后的字节码: 2)替换掉原来

【Java高级】JVM内存区域模型和加载过程

JVM内存区域模型 1.方法区 也称"永久代" ."非堆",  它用于存储虚拟机加载的类信息.常量.静态变量.是各个线程共享的内存区域.默认最小值为16MB,最大值为64MB,可以通过-XX:PermSize 和 -XX:MaxPermSize 参数限制方法区的大小. 运行时常量池:是方法区的一部分,Class文件中除了有类的版本.字段.方法.接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种符号引用,这部分内容将在类加载后放到方法区的运行时常量池中.

Java温故而知新(10)类的加载机制

类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比如热部署等,提高程序的灵活性和适应性. 1.类加载机制 我们来了解一下虚拟机如何加载Class文件. 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被直接使用的java类型,这就是虚拟机的类加载机制. 类的生命周期包括加载(Loading).验证(Verification).准

JVM自定义类加载器加载指定classPath下的所有class及jar

一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责JAVA_HOME/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作. 2.其他类加载器:由java实现,可以在方法区找到其Class对象.这里又细分为几个加载器 a).扩展类加载器(Extension ClassLoader):负责用于加载JAVA_HOM

记一次解决cmd中执行java提示&quot;找不到或无法加载主类&quot;的问题

今天遇到一个问题:在cmd命令行中,用javac编译java文件可以成功,但是用java执行却提示"找不到或无法加载主类".现将该问题的原因以及解决办法记录一下. 先理解一下系统变量path和classpath的作用. path:可执行命令的搜索路径,在该路径下搜索可以运行的程序或批处理文件. 命令行中输入一个命令,则会在path配置的目录中查找该命令,如果存在则调用该程序运行,如果不存在则提示" 'XXX' 不是内部或外部命令,也不是可运行的程序或批处理文件."

JVM进程jar包加载分析

有时在一个应用中,会依赖很多的jar包,难免会出现引用不同jar包中的同名类,或者jar包冲突,这时搞清楚: JVM启动时加载了哪些jar包 或者一个类来自哪个jar中来就非常重要了. 一.查看JVM加载了哪些jar包 启动JVM,通过如下命令获取进程号: jps -lm 1 其中参数: -l:输出main所在类的全名,如果执行的是jar包,则输出jar包路径 -m:输出jvm进程启动时传递给main函数的参数 jps还有参数-v:输出jvm进程启动时JVM参数. 使用如下命令: jinfo +

看看Spring的源码——Bean加载过程

最近几天跟同事聊起Spring的一些问题,对一些地方有些疑问,趁这两天有点空,看看Spring的源码,了解下具体的实现细节.本文基于Spring 4.0.5版本. 首先Web项目使用Spring是通过在web.xml里面配置org.springframework.web.context.ContextLoaderListener初始化IOC容器的. <listener> <listener-class>org.springframework.web.context.ContextL