JVM performance optimization - class loader, class thermal achieved manually loading

A hierarchy of class loading mechanism

Each ".java" to expand the name of the class file written are stored with the program logic to be executed, these ".java" file through the Java compiler to expand a file called ".class" the, ". Class" files store the virtual machine instruction converted Java code, when you need to use a class, the virtual machine will load its ".class" file and create corresponding class object, load class files to the virtual machine's memory, this a process known as class loading, here we need to look at the class loading process, as follows:

Jvm execution class file
file

Step one, class loading mechanism

The contents of the bytecode class files are loaded into memory, and the static data structure of the data conversion operation in the region as a method of generating a representative of the heap java.lang.Class object of this class, as a method of the class data region access entry, this process needs to participate in class loader.

When the system is running, the class loader binary data memory .class files transferred from an external memory (e.g., an optical disk, a hard disk) memory, then the CPU reads instructions and data from memory, perform an operation, and stores the calculation result . Memory acts as a "secondary" role in the process, popular speaking, if no memory, a class loader .class files binary data transferred from the external storage device directly to the CPU processing, since the processing speed of the CPU and is much larger the speed of the transferred data is likely to cause disconnection of data, it is necessary from the buffer memory.

After the class files are loaded .class zone to the runtime method, creates a heap Java.lang.Class object, the data structures are used to package the class method area, which is created during the Class object class loading each class has a corresponding object of type class, the class class constructor is private, only the JVM can create. Thus Class object is reflected by the entrance, the object can be obtained using the .class files associated with the target class specific data structures.
file
Class loading final product Class object is located in the stack (note than the target class object), the object encapsulates the class data structures in the process zone, and provides the interface access method for a data structure of the user area, i.e. Java reflection interface.

Step two, the connection process

The java class binary code into the operating state in the process of the JVM

Verify: To ensure compliance with the information loaded class JVM specification, no security issues

Preparation: Official allocate memory for the class variables (static variable) and the initial value of the class variable setting stage, which are allocated in the memory area method

Analysis: Symbol virtual machine constant pool bytes replace references cited process

Step three, initialization

Initialization phase is performed class constructor <clinit>()process approach. Class constructor <clinit>()is assigned by the operation of the automatic compiler collection classes and static variables of all classes statement blocks (static block) statements merger, code is executed from top to bottom.

When initializing a class, if you find the parent class has not been initialized, you need to trigger initialization of the parent class

Virtual opportunity to ensure a class <clinit>()method is correctly locked in a multi-threaded environment and synchronized
when the scope of a Java class static field, only the real class reputation of this field will be initialized

Second, the class hierarchy loader

Start (on Bootstrap) class loader

Extended (the Extension) class loader

System (-) class loader

file

1 start (on Bootstrap) class loader

Start class loader to load the JVM major class of their own needs, this class is loaded using the C ++ language is part of the virtual machine itself, which is responsible for <JAVA_HOME>/libthe jar package under the core libraries or -Xbootclasspath path parameters specified path loaded into memory, attention must be due to the virtual machine is loaded jar package in accordance with the file name recognition, such as rt.jar, if the file name is not recognized virtual machine, even if the jar package lib directory also throw no effect (for security reasons, Bootstrap start classes loaded only at the beginning of class package called java, javax, sun, etc.).

2, extended (the Extension) class loader

扩展类加载器是指Sun公司(已被Oracle收购)实现的sun.misc.Launcher$ExtClassLoader类,由Java语言实现的,是Launcher的静态内部类,它负责加载<JAVA_HOME>/lib/ext目录下或者由系统变量-Djava.ext.dir指定位路径中的类库,开发者可以直接使用标准扩展类加载器。

3、系统(System)类加载器

也称应用程序加载器是指 Sun公司实现的sun.misc.Launcher$AppClassLoader。它负责加载系统类路径java -classpath或-D java.class.path 指定路径下的类库,也就是我们经常用到的classpath路径,开发者可以直接使用系统类加载器,一般情况下该类加载是程序中默认的类加载器,通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器。

在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,需要注意的是,Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象,而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式即把请求交由父类处理,它一种任务委派模式,下面我们进一步了解它。

3.1、理解双亲委派模式

下面我们从代码层面了解几个Java中定义的类加载器及其双亲委派模式的实现,它们类图关系如下

file

双亲委派模式是在Java 1.2后引入的,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成,这不就是传说中的实力坑爹啊?那么采用这种模式有啥用呢?

3.1、双亲委派模式优势

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。可能你会想,如果我们在classpath路径下自定义一个名为java.lang.SingleInterge类(该类是胡编的)呢?该类并不存在java.lang中,经过双亲委托模式,传递到启动类加载器中,由于父类加载器路径下并没有该类,所以不会加载,将反向委托给子类加载器加载,最终会通过系统类加载器加载该类。但是这样做是不允许,因为java.lang是核心API包,需要访问权限,强制加载将会报出如下异常

java.lang.SecurityException: Prohibited package name: java.lang

所以无论如何都无法加载成功的。

三、类加载器间的关系

我们进一步了解类加载器间的关系(并非指继承关系),主要可以分为以下4点

  • 启动类加载器,由C++实现,没有父类。
  • 拓展类加载器(ExtClassLoader),由Java语言实现,父类加载器为null
  • 系统类加载器(AppClassLoader),由Java语言实现,父类加载器为ExtClassLoader
  • 自定义类加载器,父类加载器肯定为AppClassLoader。

1、类加载器常用方法

loadClass(String)

该方法加载指定名称(包括包名)的二进制类型,该方法在JDK1.2之后不再建议用户重写但用户可以直接调用该方法,loadClass()方法是ClassLoader类自己实现的,该方法中的逻辑就是双亲委派模式的实现,其源码如下,loadClass(String name, boolean resolve)是一个重载方法,resolve参数代表是否生成class对象的同时进行解析相关操作。

正如loadClass方法所展示的,当类加载请求到来时,先从缓存中查找该类对象,如果存在直接返回,如果不存在则交给该类加载去的父加载器去加载,倘若没有父加载则交给顶级启动类加载器去加载,最后倘若仍没有找到,则使用findClass()方法去加载(关于findClass()稍后会进一步介绍)。从loadClass实现也可以知道如果不想重新定义加载类的规则,也没有复杂的逻辑,只想在运行时加载自己指定的类,那么我们可以直接使用this.getClass().getClassLoder.loadClass("className"),这样就可以直接调用ClassLoader的loadClass方法获取到class对象。

findClass(String)

在JDK1.2之前,在自定义类加载时,总会去继承ClassLoader类并重写loadClass方法,从而实现自定义的类加载类,但是在JDK1.2之后已不再建议用户去覆盖loadClass()方法,而是建议把自定义的类加载逻辑写在findClass()方法中,从前面的分析可知,findClass()方法是在loadClass()方法中被调用的,当loadClass()方法中父加载器加载失败后,则会调用自己的findClass()方法来完成类加载,这样就可以保证自定义的类加载器也符合双亲委托模式。需要注意的是ClassLoader类中并没有实现findClass()方法的具体代码逻辑,取而代之的是抛出ClassNotFoundException异常,同时应该知道的是findClass方法通常是和defineClass方法一起使用的(稍后会分析)

defineClass(byte[] b, int off, int len)

defineClass()方法是用来将byte字节流解析成JVM能够识别的Class对象(ClassLoader中已实现该方法逻辑),通过这个方法不仅能够通过class文件实例化class对象,也可以通过其他方式实例化class对象,如通过网络接收一个类的字节码,然后转换为byte字节流创建对应的Class对象,defineClass()方法通常与findClass()方法一起使用,一般情况下,在自定义类加载器时,会直接覆盖ClassLoader的findClass()方法并编写加载规则,取得要加载类的字节码后转换成流,然后调用defineClass()方法生成类的Class对象

resolveClass(Class<?> c)

使用该方法可以使用类的Class对象创建完成也同时被解析。前面我们说链接阶段主要是对字节码进行验证,为类变量分配内存并设置初始值同时将字节码文件中的符号引用转换为直接引用。

四、热部署

For Java applications, hot deployment is to update Java class files at run time.

1. What is the principle of hot deployment

Want to know the principles of hot deployment, it is necessary to understand the loading java class. A java class files to the virtual machine object, go through the following process.

Firstly java compiler, the java byte code compiled into class file, the class loader reads the class bytecode, and then translated into class instances of an object can be generated newInstance examples.

ClassLoader class loader function, i.e. converted into byte code class instance of a class.

Java applications in all instances by the class loader are loaded from.

Usually in the system, the class is loaded by the system class loader comes, and for the same java class fully qualified name (e.g. com.csiar.soc.HelloWorld), can only be loaded once, and can not be uninstall.

This time the problem comes, if we want to uninstall java class, and replace a newer version of java class, how to do it?

Since the class loader, java classes can only be loaded once and can not be uninstalled. It is not possible to directly change the class loader? The answer is yes, we can custom class loader, and rewrite findClass method of ClassLoader. Want to achieve hot deployment can be divided into the following three steps:

  1. Destroy the custom ClassLoader
  2. Update class class file
  3. Create a new Class class ClassLoader to load the updated file.

2, hot deployment and hot load

2.1, Java links and differences hot deployment and hot load of Java

Java hot deployment and hot loaded Contact

  1. Do not restart the server compile / deploy the project
  2. Java class loader implementation based on

Java hot deployment and hot load of difference

  1. Deployment
    • Hot deployment project redeploy the server is running
    • Thermal load reload class at runtime
  2. The principle
    • Hot deployment directly to reload the entire application
    • Thermal load reload class at runtime
  3. scenes to be used
    • More heat is deployed in production environments
    • Thermal load is more of a real development environment

3, the relevant code

User classes are not modified

public class User {

    public void add() {
        System.out.println("addV1,没有修改过...");
    }
}

User updates class

public class User {

    public void add() {
        System.out.println("我把之前的user add方法修改啦!");
    }
}

Custom class loader

public class MyClassLoader extends ClassLoader {

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            // 文件名称
            String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
            // 获取文件输入流
            InputStream is = this.getClass().getResourceAsStream(fileName);
            // 读取字节
            byte[] b = new byte[is.available()];
            is.read(b);
            // 将byte字节流解析成jvm能够识别的Class对象
            return defineClass(name, b, 0, b.length);
        } catch (Exception e) {
            throw new ClassNotFoundException();
        }

    }

}

Update code

public class Hotswap {

    public static void main(String[] args)
            throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException,
            SecurityException, IllegalArgumentException, InvocationTargetException, InterruptedException {
        loadUser();
        System.gc();
        Thread.sleep(1000);// 等待资源回收
        // 需要被热部署的class文件
        File file1 = new File("F:\\test\\User.class");
        // 之前编译好的class文件
        File file2 = new File(
                "F:\\test\\test\\target\\classes\\com\\itmayiedu\\User.class");
        boolean isDelete = file2.delete();// 删除旧版本的class文件
        if (!isDelete) {
            System.out.println("热部署失败.");
            return;
        }
        file1.renameTo(file2);
        System.out.println("update success!");
        loadUser();
    }

    public static void loadUser() throws ClassNotFoundException, InstantiationException, IllegalAccessException,
            NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
        MyClassLoader myLoader = new MyClassLoader();
        Class<?> class1 = myLoader.findClass("com.test.User");
        Object obj1 = class1.newInstance();
        Method method = class1.getMethod("add");
        method.invoke(obj1);
        System.out.println(obj1.getClass());
        System.out.println(obj1.getClass().getClassLoader());
    }
}

Personal blog snail

Guess you like

Origin www.cnblogs.com/codeobj/p/12082587.html