欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Class文件和JVM的恩怨情仇

程序员文章站 2022-07-02 12:54:57
类的加载时机 现在我们例子中生成的两个.class文件都会直接被加载到JVM中吗?? 虚拟机规范则是严格规定了有且只有5种情况必须立即对类进行“初始化”(class文件加载到JVM中): 创建类的实例(new 的方式)。访问某个类或接口的静态变量,或者对该静态变量赋值,调用类的静态方法 反射的方式 ......

类的加载时机

现在我们例子中生成的两个.class文件都会直接被加载到jvm中吗??

虚拟机规范则是严格规定了有且只有5种情况必须立即对类进行“初始化”(class文件加载到jvm中):

  • 创建类的实例(new 的方式)。访问某个类或接口的静态变量,或者对该静态变量赋值,调用类的静态方法
  • 反射的方式
  • 初始化某个类的子类,则其父类也会被初始化
  • java虚拟机启动时被标明为启动类的类,直接使用java.exe命令来运行某个主类(包含main方法的那个类)
  • 当使用jdk1.7的动态语言支持时(....)

所以说:

  • java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载。这当然就是为了节省内存开销。

如何将类加载到jvm

class文件是通过类的加载器装载到jvm中的!

java默认有三种类加载器:

Class文件和JVM的恩怨情仇

 

各个加载器的工作责任:

  • 1)bootstrap classloader:负责加载$java_home中jre/lib/rt.jar里所有的class,由c++实现,不是classloader子类
  • 2)extension classloader:负责加载java平台中扩展功能的一些jar包,包括$java_home中jre/lib/*.jar或-djava.ext.dirs指定目录下的jar包
  • 3)app classloader:负责记载classpath中指定的jar包及目录中class

工作过程:

  • 1、当appclassloader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器extclassloader去完成。
  • 2、当extclassloader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给bootstrapclassloader去完成。
  • 3、如果bootstrapclassloader加载失败(例如在$java_home/jre/lib里未查找到该class),会使用extclassloader来尝试加载;
  • 4、若extclassloader也加载失败,则会使用appclassloader来加载
  • 5、如果appclassloader也加载失败,则会报出异常classnotfoundexception

其实这就是所谓的双亲委派模型。简单来说:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上。

好处:

  • 防止内存中出现多份同样的字节码(安全性角度)

特别说明:

  • 类加载器在成功加载某个类之后,会把得到的 java.lang.class类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。

类加载详细过程

加载器加载到jvm中,接下来其实又分了好几个步骤:

  • 加载,查找并加载类的二进制数据,在java堆中也创建一个java.lang.class类的对象。
  • 连接,连接又包含三块内容:验证、准备、初始化。
  • 1)验证,文件格式、元数据、字节码、符号引用验证;
  • 2)准备,为类的静态变量分配内存,并将其初始化为默认值;
  • 3)解析,把类中的符号引用转换为直接引用
  • 初始化,为类的静态变量赋予正确的初始值。
Class文件和JVM的恩怨情仇

 

jit即时编辑器

一般我们可能会想:jvm在加载了这些class文件以后,针对这些字节码,逐条取出,逐条执行-->解析器解析。

但如果是这样的话,那就太慢了!

我们的jvm是这样实现的:

  • 就是把这些java字节码重新编译优化,生成机器码,让cpu直接执行。这样编出来的代码效率会更高。
  • 编译也是要花费时间的,我们一般对热点代码做编译,非热点代码直接解析就好了。

热点代码解释:一、多次调用的方法。二、多次执行的循环体

使用热点探测来检测是否为热点代码,热点探测有两种方式:

  • 采样
  • 计数器

目前hotspot使用的是计数器的方式,它为每个方法准备了两类计数器:

  • 方法调用计数器(invocation counter)
  • 回边计数器(back edgecounter)。
  • 在确定虚拟机运行参数的前提下,这两个计数器都有一个确定的阈值,当计数器超过阈值溢出了,就会触发jit编译。
Class文件和JVM的恩怨情仇

 

回到例子中

按我们程序来走,我们的java3ytest.class文件会被appclassloader加载器(因为extclassloader和bootstrap加载器都不会加载它[双亲委派模型])加载到jvm中。

随后发现了要使用java3y这个类,我们的java3y.class文件会被appclassloader加载器(因为extclassloader和bootstrap加载器都不会加载它[双亲委派模型])加载到jvm中

 Class文件和JVM的恩怨情仇

 

 

最后

如果对java微服务、分布式、高并发、高可用、大型互联网架构技术、面试经验交流。感兴趣的话可以关注我哦!

小编也有一些资料分享给大家,对学习提升很有作用的,有关于分布式,微服务,性能优化,spring,mybatis的等源码知识点的录像视频还有spring, jvm等等的面试题,希望能够帮助到大家!

Class文件和JVM的恩怨情仇

 

 Class文件和JVM的恩怨情仇

 

 需要的可以加我的java交流群领取哦!

772300343  群主会主动给你的哒!

我是小架,我们下篇文章见!