首页编程java编程java 虚拟机什么时候加载类 Java中的类是什么时候被加载到虚拟机

java 虚拟机什么时候加载类 Java中的类是什么时候被加载到虚拟机

编程之家2023-10-1292次浏览

今天给各位分享java 虚拟机什么时候加载类的知识,其中也会对Java中的类是什么时候被加载到虚拟机进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

java 虚拟机什么时候加载类 Java中的类是什么时候被加载到虚拟机

Java中的类是什么时候被加载到虚拟机

这个问题java的比较核心的一个难题,我就针对问题做简要回答,不做深入讨论了:

1、编译和运行概念要搞清:编译即javac的过程,负责将.java文件compile成.class文件,主要是类型、格式检查与编译成字节码文件,而加载是指java*的过程,将.class文件加载到内存中去解释执行,即运行的时候才会有加载一说。

java 虚拟机什么时候加载类 Java中的类是什么时候被加载到虚拟机

2、类的加载时机,肯定是在运行时,但并不是一次性全部加载,而是按需动态,依靠反射来实现动态加载,一般来说一个class只会被加载一次,之后就会从jvm的class实例的缓存中获取,谁用谁取就可以了,不会再去文件系统中加载.class文件了。

明白1,2点就够了,再深入要等一段才能明白了。

java 虚拟机什么时候加载类 Java中的类是什么时候被加载到虚拟机

java的类加载后什么时候会被释放

java的类加载后且当使用阶段完成之后,java类就进入了卸载阶段,也就是所谓的释放。

使用阶段包括主动引用和被动引用,主动饮用会引起类的初始化,而被动引用不会引起类的初始化。

一个java类的完整的生命周期会经历加载、连接、初始化、使用、和卸载五个阶段,当然也有在加载或者连接之后没有被初始化就直接被使用的情况,如图所示:

PS:关于类的卸载,在类使用完之后,如果满足下面的情况,类就会被卸载:

该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。

加载该类的ClassLoader已经被回收。

该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。

如果以上三个条件全部满足,jvm就会在方法区垃圾回收的时候对类进行卸载,类的卸载过程其实就是在方法区中清空类信息,java类的整个生命周期就结束了。

class 类 什么 时候被 加载 java虚拟机内存

编写的java文件经过编译之后形成字节码文件,当你的程序在运行中调用到该class类的时候,通过ClassLoader进行加载。下面详细介绍下。

class文件从加载到jvm内存中开始,到卸载出内存为止,他的整个生命周期(整个加载过程)包括:加载,验证,准备,解析,初始化,使用和卸载。其中验证,准备,解析三个合称为连接。下面重点说一下加载过程。

加载过程:

1、通过一个类的全限定名来获取定义此类的二进制字节流

2、将字节流所代表的静态存储结构转化为方法区的运行时存储结构

3、在java堆中生成一个代表该类的对象,作为方法区这些数据的访问入口

验证:

1、文件格式验证:是否以魔数0xCAFEBABE开头,class文件的主次版本号是否在当前jvm处理范围之内,常量池的常量中是否有不被支持的类型,指向常量中的索引值有无不存在的常量,等

2、元数据验证:对字节码描述的信息进行语义分析,保证符合java规范。如是否有父类,是否继承了不允许继承的类,如果不是抽象类,是否实现了所有未实现的方法。等

3、字节码验证:数据流和控制流分析。主要针对类的方法体。

4、符号引用验证:如符号引用中通过字符串描述的全限定名是否能够找到对应的类等

准备:

该阶段正式为类变量分配内存并设置初始值。内存在方法区中分配。这里说的初始值是通常情况下说的零值。

解析:

虚拟机将常量池中的符号引用替换为直接引用的过程。包括:

1、类或接口的解析

2、字段解析

3、类方法解析

4、接口方法解析

初始化:

类初始化阶段是类加载过程的最后一步,除了加载阶段用户可以通过自定义加载器参与外,其余动作完全由虚拟机指导控制。到了初始化阶段,才真正开始执行类中定义的java程序代码(字节码)。在准备阶段,变量已经赋过一次系统默认值,而在初始化阶段,则是根据程序制定的主观计划去初始化类变量和其他资源,即初始化阶段是执行类构造器<clinit>()方法的过程。<clinit>是在编译java源码时,按照静态块和静态变量赋值语句的顺序生成的。如果类没有静态块也没有为静态变量赋值,就不会生成<clinit>方法,该方法只能被虚拟机调用。

Java垃圾回收:GC在什么时候对什么做了什么

GC在什么时候对什么做了什么?

要回答这个问题,先了解下GC的发展史、jvm运行时数据区的划分、jvm内存分配策略、jvm垃圾收集算法等知识。

先说下jvm运行时数据的划分,粗暴的分可以分为堆区(Heap)和栈区(Stack),但jvm的分法实际上比这复杂得多,大概分为下面几块:

1、程序计数器(Program Conuter Register)

程序计数器是一块较小的内存空间,它是当前线程执行字节码的行号指示器,字节码解释工作器就是通过改变这个计数器的值来选取下一条需要执行的指令。它是线程私有的内存,也是唯一一个没有OOM异常的区域。

2、Java虚拟机栈区(Java Virtual Machine Stacks)

也就是通常所说的栈区,它描述的是Java方法执行的内存模型,每个方法被执行的时候都创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等。每个方法被调用到完成,相当于一个栈帧在虚拟机栈中从入栈到出栈的过程。此区域也是线程私有的内存,可能抛出两种异常:如果线程请求的栈深度大于虚拟机允许的深度将抛出StackOverflowError;如果虚拟机栈可以动态的扩展,扩展到无法动态的申请到足够的内存时会抛出OOM异常。

3、本地方法栈(Native Method Stacks)

本地方法栈与虚拟机栈发挥的作用非常相似,区别就是虚拟机栈为虚拟机执行Java方法,本地方法栈则是为虚拟机使用到的Native方法服务。

4、堆区(Heap)

所有对象实例和数组都在堆区上分配,堆区是GC主要管理的区域。堆区还可以细分为新生代、老年代,新生代还分为一个Eden区和两个Survivor区。此块内存为所有线程共享区域,当堆中没有足够内存完成实例分配时会抛出OOM异常。

5、方法区(Method Area)

方法区也是所有线程共享区,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。GC在这个区域很少出现,这个区域内存回收的目标主要是对常量池的回收和类型的卸载,回收的内存比较少,所以也有称这个区域为永久代(Permanent Generation)的。当方法区无法满足内存分配时抛出OOM异常。

6、运行时常量池(Runtime Constant Pool)

运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。

垃圾收集(Garbage Collection)并不是Java独有的,最早是出现在Lisp语言中,它做的事就是自动管理内存,也就是下面三个问题:

1、什么时候回收

2、哪些内存需要回收

3、如何回收

1、什么时候回收?

上面说到GC经常发生的区域是堆区,堆区还可以细分为新生代、老年代,新生代还分为一个Eden区和两个Survivor区。

1.1对象优先在Eden中分配,当Eden中没有足够空间时,虚拟机将发生一次Minor GC,因为Java大多数对象都是朝生夕灭,所以Minor GC非常频繁,而且速度也很快;

1.2 Full GC,发生在老年代的GC,当老年代没有足够的空间时即发生Full GC,发生Full GC一般都会有一次Minor GC。大对象直接进入老年代,如很长的字符串数组,虚拟机提供一个-XX:PretenureSizeThreadhold参数,令大于这个参数值的对象直接在老年代中分配,避免在Eden区和两个Survivor区发生大量的内存拷贝;

1.3发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则进行一次Full GC,如果小于,则查看HandlePromotionFailure设置是否允许担保失败,如果允许,那只会进行一次Minor GC,如果不允许,则改为进行一次Full GC。

2、哪些内存需要回收

jvm对不可用的对象进行回收,哪些对象是可用的,哪些是不可用的?Java并不是采用引用计数算法来判定对象是否可用,而是采用根搜索算法(GC Root Tracing),当一个对象到GC Roots没有任何引用相连接,用图论的来说就是从GC Roots到这个对象不可达,则证明此对象是不可用的,说明此对象可以被GC。对于这些不可达对象,也不是一下子就被GC,而是至少要经历两次标记过程:如果对象在进行根搜索算法后发现没有与GC Roots相连接的引用链,那它将会第一次标记并且进行一次筛选,筛选条件是此对象有没有必要执行finalize()方法,当对象没有覆盖finalize()方法或者finalize()方法已经被虚拟机调用执行过一次,这两种情况都被视为没有必要执行finalize()方法,对于没有必要执行finalize()方法的将会被GC,对于有必要有必要执行的,对象在finalize()方法中可能会自救,也就是重新与引用链上的任何一个对象建立关联即可。

3、如何回收

选择不同的垃圾收集器,所使用的收集算法也不同。

在新生代中,每次垃圾收集都发现有大批对象死去,只有少量存活,则使用复制算法,新生代内存被分为一个较大的Eden区和两个较小的Survivor区,每次只使用Eden区和一个Survivor区,当回收时将Eden区和Survivor还存活着的对象一次性的拷贝到另一个Survivor区上,最后清理掉Eden区和刚才使用过的Survivor区,Eden和Survivor的默认比例是8:1,可以使用-XX:SurvivorRatio来设置该比例。

而老年代中对象存活率高,没有额外的空间对它进行分配担保,必须使用“标记-清理”或“标记-整理”算法。

OK,关于java 虚拟机什么时候加载类和Java中的类是什么时候被加载到虚拟机的内容到此结束了,希望对大家有所帮助。

java编程app看什么书,学java看什么书java继承的目的是什么意思,java继承的目的是什么