JVM----基础

Posted yanxiaoge

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM----基础相关的知识,希望对你有一定的参考价值。

我们执行一个类

首先javac命令编译这个类(对编译原理我们不需要做深入了解)

在java命令启动虚拟机对.class文件进行加载和执行

 

类加载或类初始化

  当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载、连接、初始化3个步骤来对该类进行初始化。如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化。

                                                                   技术图片

 

 

 

一、类加载过程

1.加载    

  将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构(包含类的所有的信息),在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口,就是Class对象会指向这个方法区中的数据,并且如果外部程序只能通过Class对象来进行访问。这个过程需要类加载器参与。也就是说,当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象(所有的对象都是通过这个Class对象来进行初始化的)

  类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础,JVM提供的这些类加载器通常被称为系统类加载器。除此之外,开发者可以通过继承ClassLoader基类来创建自己的类加载器。

  通过使用不同的类加载器,可以从不同来源加载类的二进制数据,通常有如下几种来源

    从本地文件系统加载class文件,这是前面绝大部分示例程序的类加载方式。
    从JAR包加载class文件,这种方式也是很常见的,前面介绍JDBC编程时用到的数据库驱动类就放在JAR文件中,JVM可以从JAR文件中直接加载该class文件。
    通过网络加载class文件。
    把一个Java源文件动态编译,并执行加载。
  类加载器通常无须等到“首次使用”该类时才加载该类,Java虚拟机规范允许系统预先加载某些类。

2.链接

  当类被加载之后,系统为之生成一个对应的Class对象,接着将会进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中。类连接又可分为如下3个阶段。

  (1)验证

    验证阶段用于检验被加载的类是否有正确的内部结构,并和其他类协调一致。Java是相对C++语言是安全的语言,例如它有C++不具有的数组越界的检查。这本身就是对自身安全的一种保护。验证阶段是Java非常重要的一个阶段,它会直接的保证应用是否会被恶意入侵的一道重要的防线,越是严谨的验证机制越安全。验证的目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。其主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。

       四种验证做进一步说明:

    文件格式验证:主要验证字节流是否符合Class文件格式规范,并且能被当前的虚拟机加载处理。例如:主,次版本号是否在当前虚拟机处理的范围之内。常量池中是否有不被支持的常量类型。指向常量的中的索引值是否存在不存在的常量或不符合类型的常量。

    元数据验证:对字节码描述的信息进行语义的分析,分析是否符合java的语言语法的规范。

    字节码验证:最重要的验证环节,分析数据流和控制,确定语义是合法的,符合逻辑的。主要的针对元数据验证后对方法体的验证。保证类方法在运行时不会有危害出现。

    符号引用验证:主要是针对符号引用转换为直接引用的时候,是会延伸到第三解析阶段,主要去确定访问类型等涉及到引用的情况,主要是要保证引用一定会被访问到,不会出现类等无法访问的问题。

  (2)准备

    类准备阶段负责为类的静态变量(static)分配内存(这些内存都在方法区中分配),并设置默认初始值。

    比如public static int a=3; 在准备阶段a=0(设置默认值),a=3是在初始化的时候。

  (3)解析   

    将类的二进制数据中的符号引用替换成直接引用。说明一下:符号引用:符号引用是以一组符号来描述所引用的目标,符号可以是任何的字面形式的字面量,只要不会出现冲突能够定位到就行。布局和内存无关。直接引用:是指向目标的指针,偏移量或者能够直接定位的句柄。该引用是和内存中的布局有关的,并且一定加载进来的。

    符号引用(抽象):a---->b,表示a会去定位到b。但是不知道b的具体位置

    直接引用(具体):a(b的位置在地球-->中国-->北京-->........)

    一个类中包含了很多常量,不光我们修饰的(final),比如类名,方法名,参数名a,变量名b和c,“aa”和1,类型名称void String public都是属于常量。在方法区中每一个类都有一个常量池。这个常量池放置了符号引用,但是需要将符号引用替换成直接引用之后,类才具备初始化的条件。

public class Demo01 
    public void test(int a)
        String  b = "aa";
        int c = 1;
    
 

3.初始化

  初始化阶段是执行类构造器 <clinit>() 方法的过程。类构造器 <clinit>() 方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的。(初始化是为类的静态变量赋予正确的初始值)
  当初始化一个类的时候,如果发现其父类还没有进行过初始化、则需要先出发其父类的初始化虚拟机会保证一个类的<clinit>0方法在多线程环境中被正确加锁和同步。
  当访问一个Java类的静态域时,只有真正声明这个域的类才会被初始化。

 

 

 

 

 

 

 

 

 

 

 

 

 


原文链接:https://blog.csdn.net/m0_38075425/article/details/81627349

 

以上是关于JVM----基础的主要内容,如果未能解决你的问题,请参考以下文章

jvm基础--JVM内存模型

jvm基础--GC垃圾回收机制

JVM 基础知识

JVM基础

JVM基础:深入学习JVM堆与JVM栈(转)

JVM基础认知篇(上)