java-初识JVM运行及类加载过程

简介:

类加载机制:

      JVM把class文件加载到内存,并对数据进行校验,解析和初始化,最终形成JVM可以直接使用的Java类型的过程。

类加载全过程:

  加载:

       将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问路口,这个过程需要类加载器参与。

  链接:  将Java类的二进制代码合并到JVM的运行状态之中的过程。

  (1)验证:确保加载的类信息符合JVM规范,没有安全方面的问题。

  (2)准备:正式为类变量(static变量)分配内存并设置变量初始值的阶段,这些内存都将在方法区中进行分配。

  (3)解析:虚拟机中常量池的符号引用替换为直接引用的过程。

 初始化:

    初始化阶段是执行类构造器方法的过程,类构造器方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合成的。

    当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先出发其父类的初始化。

    虚拟机会保证一个类的方法在多线程环境中被正确加锁和同步。

    当访问一个Java类的静态域时,只有真正声明这个域的类才会被初始化。

类加载器的层次结构(树状结构):

(1)引导类加载器:用来加载Java的核心库,是由原生代码来实现的,并不继承自java.lang.ClassLoader,加载扩展类和应用程序类加载器,并指定它们的父类加载器。

(2)扩展类加载器:用来加载Java的扩展库,Java虚拟机的实现会提供一个扩展库目录,该类加载器在此目录里面查找并加载Java类。由sun.misc.Launcher$ExtClassLoader实现。

(3)应用程序类加载器:根据Java应用的类路径(classpath,java.class.path)路类实现,一般来说,Java应用的类都是由它来完成加载的。由sun.misc.Launcher$AppClassLoader实现。

(4)自定义类加载器:开发人员通过继承java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。

Java.lang.ClassLoader类的相关介绍:

作用:

(1)根据一个指定的类的名称,找到或者生成对应的字节代码,然后从这些字节代码中定义出一个java类,即java.lang.Class类的一个实例。

(2)负责加载Java应用所需的资源,如图像文件或配置文件等等。

相关方法:

  •   getParent():返回该类加载器的父类加载器。
  •   loadClass(String name):加载名为name的类,返回的结果是java.lang.Class类的一个实例。
  •   findClass(String name):查找名为name的类,返回的结果是java.lang.Class类的一个实例。
  •   findLoadedClass(String name):查找名称为name的已经被加载的类,返回的结果是java.lang.Class类的一个实例。
  •   defineClass(String name,byte[] b,int off,int len):将字节数组中b的内容转换成java类,返回的结果为java.lang.Class类的实例,方法为final。
  •   resolveClass(Class<?> c):链接指定的java类。

Ps:对于以上给出的方法,表示类名称的name参数的值为类的二进制名称。

类加载器的代理模式:

代理模式:交给其他加载器来加载指定的类。

双亲委托机制(父类加载器优先加载):

  •   某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次追溯,直到最高的类加载器,如果父类加载器可以完成类加载的任务,就成功返回,只有父类加载器无法完成此加载任务时,才自己去加载。
  •   双亲委托机制是为了保证Java核心库的类型安全。(使得不会出现用户自己能够定义java.lang.Object类的情况)
  •   类加载器除了用于加载类,也是安全的最基本的屏障。

线程上下文类加载器:

1:系统类加载器或叫应用类加载器

2:当前加载器

3:当前线程类加载器

线程类加载器是为了抛弃双亲委派加载链机制,每一个线程类加载器都有一个关联的上下文加载器,如果使用new Thread()新建新的线程,新线程将继承其父进程的上下文类加载器,如果程序对线程上下文类加载器没有任何改动,程序中所有的线程都将使用系统类加载器作为上下文类加载器。

Thread.currentThread().getContextClassLoader();

Thread.currentThread().setContextClassLoader();

OSGI技术原理介绍:

       面向java的动态模块系统,为开发人员提供了面向服务华基于组件的运行环境,并提供标准的方式用来管理软件的生命周期,已经被实现和部署在很多产品上。

原理:

      OSGI中的每一个模块都包含Java包和类,模块可以声明它所依赖的需要导入的其他模块的Java包和类,也可以声明导出自己的包和类,供其他模块使用。需要能够隐藏和共享一个模块中的某些Java包和类。OSGI特有的类加载器机制可以实现,每一个模块都有对应的类加载器,它负责加载模块自己包含的Java包和类。当它需要加载Java核心库的类时(以java开头的包和类),它会代理给父类加载器(通常是由启动类加载器)来完成的。当它需要加载所导入的Java类时,它会代理给导出此Java类的模块来完成加载,模块也可以显式的声明某些Java包和类,必须由父类加载器来加载,只需设置系统属性:org.osgi.framework.bootdelegation的值即可。

类加载全过程图示:

简单分析类加载器作用:

内存分析:

 1 package com.etc;
 2 
 3 public class JVM {
 4     
 5     static {
 6         System.out.println("静态代码块B!");
 7     }
 8     public static void main(String[] args) {
 9         NewTest test=new NewTest();
10 
11     }
12 }
13 class  NewTest{ 
14     static { 
15         System.out.println("静态代码块A");
16     }
17     void test() {
18         System.out.println("测试方法!");
19     }
20 }

效果截图:

由上面的截图可以看出来,类再被加载的过程中首先加载的是该类下面包含的静态代码块然后加载主方法里面的所有属性。

原文地址:https://www.cnblogs.com/weekstart/p/10845608.html