谈谈对JVM的理解(一)

#谈谈对JVM的理解(一)
1、Java虚拟机与程序的生命周期
  (1):程序正常执行完,进程结束
  (2):System.exit()方法来终止程序执行,传入参数为0,代表正常退出
  (3):程序出现异常或者错误导致虚拟机进程退出
  (4):操作系统出现错误导致虚拟机进程退出
2、类的加载、连接以及初始化
  (1)加载:查找并将磁盘上的.class文件(字节码文件,二进制数据)加载到内存中
  (2)连接:
    1.验证:验证被加载类的准确性
    2.准备:为类的静态变量分配内存以及初始化为默认值(此时a的值为0)
    3.解析:将类中的符号引用转换为直接引用
  (3)初始化:为类的静态变量赋予正确的初始值(此时a的值为3)
  public class test {
    private static int a =3;
  }
3、Java程序对类的使用方式可分为两种:主动使用和被动使用,所有的Java虚拟机实现必须在每个类或接口被Java程序"首次主动使用"时才初始化它们。
  主动使用:(六种)
    1.创建类的实例
    2.访问某个类或接口的静态变量(如果是编译是的常量,则不会对这个类做初始化操作),或者对该静态变量赋值
    3.掉用类的静态方法
    4.反射(Class.forName(“com.wuxin.test”))
    5.初始化一个类的子类
    6.Java虚拟机启动时被标明为启动类
  被动使用:除了主动使用之外的就是被动使用.都不会执行类的初始化
4、类的加载
  类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区中,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区中的数据结构。
5、加载.class文件的方式
  1.从本地系统中直接加载
  2.通过网络下载.class文件(URLClassLoader)
  3.从zip,jar等归档文件中加载.class文件
  4.从专有数据库中提取.class文件
  5.将Java源文件动态编译成.class文件
6、类的加载器
  (1):Java虚拟机自带的加载器
    1.根类加载器(Bootstrap) C++实现的,无法在Java代码中获得这个类
    2.扩展类加载器(Extension) Java实现的
    3.系统类加载器(System)又叫应用加载器 Java实现的
  (2):用户自定义类加载器
    1.java.lang.ClassLoader的子类
    2.用户可以定制类的加载方式
  类加载器不需要等到某个类被"首次主动使用"时再加载它
7、JVM规范
  JVM规范允许类加载在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)。如果这个类一直没有被程序主动使用,那么类加载就不会报告错误
8、类的连接
  类被加载后,进入连接阶段,连接就是将已经读入内存的类的二进制数据合并到虚拟机的运行环境中去。
9、类的验证
  1.类文件的结构检查
  2.语义检查
  3.字节码验证
  4.二进制兼容性的验证
10、类的初始化步骤
  (1)假如这个类还没有被加载和连接,那就先进行加载和连接。
  (2)假如类存在直接的父类,并且这个父类还没有被初始化,那就先初始化直接的父类。
  (3)假如类中存在初始化语句,那就依次执行这些初始化语句。
  (4)当Java虚拟机初始化一个类时,要求它的所有父类都已经被初始化,但是这条规则并不适用于接口。
    1.在初始化一个类时,并不会先初始化它所实现的接口。
    2.在初始化一个接口时,并不会先初始它所实现的接口。因此,一个父接口并不会因为它的子接口或者实现类的初始化而初始化。只有当程序首次使用特定接口的静态变量时,才会导致该接口的初始化。
11、类的初始化时机
  1.只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才可以认为是对类或接口的主动使用。
  2.调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。
12、JVM自带类加载器之间的关系;根类加载器->扩展类加载器->系统类加载器->用户自定义类加载器。
13、类加载的父委托机制
  1.在父亲委托机制中,各个加载器按照父子关系形成了树形结构,除了根类加载器以外,其余的类加载器都有且只有一个父加载器。在加载过程中,首先请求父级类加载器加载class文件,这样一层层的往上走,如果父加载器加载不了,再自己去加载。
  2.若有一个类加载器能成功加载Sample类,那么这个类加载器被称为定义类加载器,所有能成功返回Class对象的引用的类加载器(包括定义类加载器)都被称为初始类加载器。
  3.当生成一个自定义的类加载器实例时,如果没有指定它的父加载器,那么系统类加载器就将成为该类加载器的父加载器。
  4.父亲委托机制的优点是能够提供软件系统的安全性。因为在此机制下,用户自定义的类加载器不可能加载应该由父加载器加载的可靠类,从而防止不可靠甚至恶意的代码代替由父加载器加载的可靠代码。例如java.lang.Object类总是由根类加载器加载,其他任何用户自定义的类加载器都不可能加载含有恶意代码的java.lang.Object类。
14、命名空间
  每个类加载器都有自己的命名空间,命名空间由该加载器及所有父加载器加载的类组成。在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类。在不同的命名空中,有可能会出现类的完整名字(包括类的包名)相同的两个类。
不同类加载器加载类要互相访问类中的方法和属性,利用反射机制是可以做的到的,但不能直接访问。
15、运行时包
  由同一类加载器加载的属于相同包的类组成了运行时包。决定两个类是不是属于同一个运行时包,不仅要看它们的包名是否相同,还要看定义类加载器是否相同。只有属于同一运行时包的类才能互相访问包可见(即默认访问级别)的类和类成员。这样的限制能避免用户自定义的类冒充核心类库的类,去访问核心类库的包可见成员。假设用户自己定义了一个类java.lang.Spy,并由用自定义的类加载器加载,由于java.lang.Spy和核心类库java.lang.*由不同的加载器加载,它们属于不同的运行时包,所以ava.lang.Spy不能访问核心类库java.lang包中的包可见成员。
16、类的卸载
  (1)当Sample类被加、连接和初始化后,它的生命周期就开始了。当代表Sample类的Class对象不再被引用,即不可触及时,Class对象就会结束生命周期,Sample类在方法区内的数据也会被卸载,从而结束Sample类的生命周期。由此可见,一个类何时结束生命周期,取决于代表它的Class对象何时结束生命周期
  (2)由Java虚拟机自带的类加载器加载的类,在虚拟生命周期中,始终不会被卸载,Java自带的类加载器包括:根类加载器,扩展类加载器,系统类加载器。Java虚拟机本身会一直引用这些类加载器,这些类加载器会一直引用它们加载的类的Class对象,这些Class对象始终是可以触及的。自己定义的类加载是可以被卸载的。
  (3)在类加载器的内部实现,用一个Java集合来存放所加载类的引用,另一方面,一个类的Class对象总是会引用它的类加载器,通过getClassLoader()来获取它的类加载器,类的Class对象和它的类加载器两者是双向关联关系。一个类的实例总是引用代表这个类的Class对象,可以通过getClass()和静态方法.class获取类的Class对象。

猜你喜欢

转载自blog.csdn.net/qq_38019655/article/details/82289013