JVM进阶

JVM进阶(一)

Java bytecode 由单字节(byte)的指令组成,理论上最多支持 256 个操作码(opcode)。实际上 Java 只使用了200左右的操作码, 还有一些操作码则保留给调试操作。
根据指令的性质,主要分为四个大类:

  1. 栈操作指令,包括与局部变量交互的指令
  2. 程序流程控制指令
  3. 对象操作指令,包括方法调用指令
  4. 算术运算以及类型转换指令

JVM三大基本技术:字节码技术、类加载器、jvm内存结构

字节码运行时的结构

image-20221129151356868

本地栈里面存有很多个栈桢,调用一个方法创建一个栈桢,一个方法调用另一个方法也会创建一个栈桢,所以会有很多的栈桢

Local variables 本地

image-20221129161755695

方法调用的过程中需要的常量从常量池里面拿,需要的变量从常量池中压入操作数栈中,操作后写入本地局部变量

想要深入了解字节码技术,我们需要先对字节码的执行模型有所了解。

JVM是一台基于栈的计算机器。每个线程都有一个独属于自己的线程栈(JVM stack),用于存储 栈帧

(Frame)。每一次方法调用,JVM都会自动创建一个栈帧。 栈帧 由 操作数栈 , 局部变量数组 以及一

个 class引用 组成。 class引用 指向当前方法在运行时常量池中对应的class)。

image-20221129164110120

new + 操作数 + 操作数 所以 new 后面只有过一个操作数的时候要补00

实际上 new dup 都是帮助人来阅读的辅助 对于计算机来说 new 是bb 187

image-20221129232723659

iconst 表示int类型的常量 istore_2 表示吧常量放到2位置

算数操作码与类型转换

image-20221130140714380

image-20221130140900179

方法调用的指令

invokestatic ,顾名思义,这个指令用于调用某个类的静态方法,这也是方法调用指令中最快的一

个。

invokespecial , 我们已经学过了, invokespecial 指令用来调用构造函数,但也可以用于调用

同一个类中的 private 方法, 以及可见的超类方法。(父类的Object方法)

invokevirtual ,如果是具体类型的目标对象, invokevirtual 用于调用公共,受保护和打包

私有方法。

invokeinterface ,当要调用的方法属于某个接口时,将使用 invokeinterface 指令。

那么 invokevirtual 和 invokeinterface 有什么区别呢?这确实是个好问题。 为什么需要

invokevirtual 和 invokeinterface 这两种指令呢? 毕竟所有的接口方法都是公共方法, 直接

使用 invokevirtual 不就可以了吗?

demo

iconst 是一个入栈指令,其作用是用来将 int 类型的数字、取值在 -15 之间的整数压入栈中,5以上是使用操作码+2字节操作数

istore 是一个存储指令,其作用是 store_1将-1从操作数栈存储到局部变量表 第2个位置

iload 是从局部变量第x个位置加载到操作数栈顶

image-20221130144406901

代码实现的步骤:

1.将int类型的a 加入栈中,将a存储到本地变脸表中的第一个位置

2.将int类型的b 加入栈中,将b存储到本地变脸表中的第一个位置

3.将a、b加载到操作数栈中

4.执行+的操作

5.1.将int类型的a 加入栈中,将a存储到本地变脸表中的第一个位置

6.执行*的操作

7.将结果存储到本地变脸表中的第三个位置

8.返回

类加载器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pgsJtE2i-1671374994119)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20221201083749318.png)]

会发生类加载的情况

当虚拟机启动时,初始化用户指定的主类,就是启动执行的 main方法所在的类;

当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类,就是new一个类的时候要初始化;

当遇到调用静态方法的指令时,初始化该静态方法所在的类;

当遇到访问静态字段的指令时,初始化该静态字段所在的类;

子类的初始化会触发父类的初始化;

如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初 始化,会触发该接口的初始化;

使用反射 API 对某个类进行反射调用时,初始化这个类,其实跟前面一样,反射调用要么是已经有实例了,要么是静态方法,都需要初始化;

当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类

不会发生类加载的情况

通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。

定义对象数组,不会触发该类的初始化。(空引用)

常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触发定义常量所在的类。 (相当于是一个标记)

通过类名获取Class对象,不会触发类的初始化,Hello.class不会让Hello类初始化。

通过Class.forName加载指定类时,如果指定参数initialize为false时,也不会触发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。Class.forName(“jvm.Hello”)默认会加载Hello类。 (默认是初始化的)

通过ClassLoader默认的loadClass方法,也不会触发初始化动作(加载了,但是不初始化)

类加载器

image-20221201092948139

  1. 启动类加载器(bootstrap class loader): 它用来加载 Java 的核心类,是用原生 C++代码来实现的,并不继承自 java.lang.ClassLoader(负责加载JDK中 jre/lib/rt.jar里所有的class)。它可以看做是JVM自带的,我们再代码层面无法直接获取到启动类加载器的引用,所以不允许直接操作它, 如果打印出来就是个 null 。举例来说,java.lang.String是由启动类加载器加载的,所以String.class.getClassLoader()就会返回null。但是后面可以看到可以通过命令行 参数影响它加载什么。

    image-20221201094344941

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SnfjUowR-1671374994120)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20221201135854509.png)]

  2. 扩展类加载器(extensions class loader):它负责加载JRE的扩展目录,lib/ext 或者由java.ext.dirs系统属性指定的目录中的JAR包的类,代码里直接获取它的父 类加载器为null(因为无法拿到启动类加载器)。

  3. 应用类加载器(app class loader):它负责在JVM启动时加载来自Java命令的­ classpath或者­cp选项、java.class.path系统属性指定的jar包和类路径。在应用程序代码里可以通过ClassLoader的静态方法getSystemClassLoader()来获取应用类加载器。如果没有特别指定,则在没有使用自定义类加载器情况下,用户自定义的类都由此加载器加载。(自己编写的类和该类依赖的类)

类加载器的特点

  1. 双亲委托(双亲委派):当一个自定义类加载器需要加载一个类,比如java.lang.String,它很懒,不会一上来就直接试图加载它,而是先委托自己的父加载器去加载,父加载器如果发现自己还有父加载器,会一直往前找,这样只要上级加载器,比如启动类加载器已经加载了某个类比如java.lang.String,所有的子加载器都不需要自己加载了。如果几个类加载器都没有加载到指定名称的类,那么会抛出ClassNotFountException异常。

  2. 负责依赖:如果一个加载器在加载某个类的时候,发现这个类依赖于另外几个类或接口,也会去尝试加载这些依赖项。

  3. 缓存加载:为了提升加载效率,消除重复加载,一旦某个类被一个类加载器加载,那么它会缓存这个加载结果,不会重复加载

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wQ4VGVdr-1671374994120)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20221201134040484.png)]

充要类是ClassLoader,实现类是URLClassLoader,子类是扩展类加载器是应用类加载器,也就是都是通过URL加载的

类加载器细节路径

这个地方我们能看到点是:

1.各个类加载的路径

2.子类是扩展类加载器是应用类加载器的父类是URLClassLoader

3.子类可以看到父类加载过的类的路径

import sun.misc.Launcher;

import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;

/**
 * @Description : TODO
 * @Author : 
 * @Date : 2022/12/1 1:50 PM
 * @Version : 1.0
 **/
public class ClassLoaderTest {
    public static void main(String[] args) {
        URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
        System.out.println("启动类加载器");
        for (URL url: urLs){
            System.out.println(" === > " + url.toExternalForm());
        }
        //扩展类加载器
        pringtClassloader("扩展类加载器",ClassLoaderTest.class.getClassLoader().getParent());
        //应用类加载器
        pringtClassloader("应用类加载器",ClassLoaderTest.class.getClassLoader());
    }
    private static void pringtClassloader(String name,ClassLoader classLoader){
        System.out.println();
        if (null != classLoader){
            System.out.println(name + "Classloader -> " + classLoader.toString());
            printURLForClassloader(classLoader);
        }else {
            System.out.println(name + "Classloader -> ");
        }
    }
    private static void  printURLForClassloader(ClassLoader classLoader){
        Object ucp = insightField(classLoader,"ucp");
        Object path = insightField(ucp,"path");
        List paths = (List) path;
        for (Object p : paths){
            System.out.println(" ===> " + p.toString());
        }
    }
    private static Object insightField(Object obj, String fName){
        Field f = null;
        try {
            if (obj instanceof URLClassLoader) {
                f = URLClassLoader.class.getDeclaredField(fName);
            } else {
                f = obj.getClass().getDeclaredField(fName);
            }
            f.setAccessible(true);
            return f.get(obj);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return obj;
    }

}
/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=58232:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/rt.jar:/Users/zhaokaijie/IdeaProjects /scms-mock/target/classes:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter-web/2.7.2/spring-boot-starter-web-2.7.2.jar:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter/2.7.2/spring-boot-starter-2.7.2.jar:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot/2.7.2/spring-boot-2.7.2.jar:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.7.2/spring-boot-starter-logging-2.7.2.jar:/Users/zhaokaijie/.m2/repository/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar:/Users/zhaokaijie/.m2/repository/ch/qos/logback/logback-core/1.2.11/logback-core-1.2.11.jar:/Users/zhaokaijie/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.17.2/log4j-to-slf4j-2.17.2.jar:/Users/zhaokaijie/.m2/repository/org/apache/logging/log4j/log4j-api/2.17.2/log4j-api-2.17.2.jar:/Users/zhaokaijie/.m2/repository/org/slf4j/jul-to-slf4j/1.7.36/jul-to-slf4j-1.7.36.jar:/Users/zhaokaijie/.m2/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar:/Users/zhaokaijie/.m2/repository/org/yaml/snakeyaml/1.30/snakeyaml-1.30.jar:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.7.2/spring-boot-starter-json-2.7.2.jar:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.13.3/jackson-databind-2.13.3.jar:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.13.3/jackson-annotations-2.13.3.jar:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.13.3/jackson-core-2.13.3.jar:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.13.3/jackson-datatype-jdk8-2.13.3.jar:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.13.3/jackson-datatype-jsr310-2.13.3.jar:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.13.3/jackson-module-parameter-names-2.13.3.jar:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/2.7.2/spring-boot-starter-tomcat-2.7.2.jar:/Users/zhaokaijie/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.65/tomcat-embed-core-9.0.65.jar:/Users/zhaokaijie/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/9.0.65/tomcat-embed-el-9.0.65.jar:/Users/zhaokaijie/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.65/tomcat-embed-websocket-9.0.65.jar:/Users/zhaokaijie/.m2/repository/org/springframework/spring-web/5.3.22/spring-web-5.3.22.jar:/Users/zhaokaijie/.m2/repository/org/springframework/spring-beans/5.3.22/spring-beans-5.3.22.jar:/Users/zhaokaijie/.m2/repository/org/springframework/spring-webmvc/5.3.22/spring-webmvc-5.3.22.jar:/Users/zhaokaijie/.m2/repository/org/springframework/spring-aop/5.3.22/spring-aop-5.3.22.jar:/Users/zhaokaijie/.m2/repository/org/springframework/spring-context/5.3.22/spring-context-5.3.22.jar:/Users/zhaokaijie/.m2/repository/org/springframework/spring-expression/5.3.22/spring-expression-5.3.22.jar:/Users/zhaokaijie/.m2/repository/io/netty/netty-all/4.1.6.Final/netty-all-4.1.6.Final.jar:/Users/zhaokaijie/.m2/repository/cn/hutool/hutool-all/5.4.6/hutool-all-5.4.6.jar:/Users/zhaokaijie/.m2/repository/com/baomidou/mybatis-plus-boot-starter/3.3.1/mybatis-plus-boot-starter-3.3.1.jar:/Users/zhaokaijie/.m2/repository/com/baomidou/mybatis-plus/3.3.1/mybatis-plus-3.3.1.jar:/Users/zhaokaijie/.m2/repository/com/baomidou/mybatis-plus-extension/3.3.1/mybatis-plus-extension-3.3.1.jar:/Users/zhaokaijie/.m2/repository/com/baomidou/mybatis-plus-core/3.3.1/mybatis-plus-core-3.3.1.jar:/Users/zhaokaijie/.m2/repository/com/baomidou/mybatis-plus-annotation/3.3.1/mybatis-plus-annotation-3.3.1.jar:/Users/zhaokaijie/.m2/repository/com/github/jsqlparser/jsqlparser/3.1/jsqlparser-3.1.jar:/Users/zhaokaijie/.m2/repository/org/mybatis/mybatis/3.5.3/mybatis-3.5.3.jar:/Users/zhaokaijie/.m2/repository/org/mybatis/mybatis-spring/2.0.3/mybatis-spring-2.0.3.jar:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.7.2/spring-boot-autoconfigure-2.7.2.jar:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter-jdbc/2.7.2/spring-boot-starter-jdbc-2.7.2.jar:/Users/zhaokaijie/.m2/repository/com/zaxxer/HikariCP/4.0.3/HikariCP-4.0.3.jar:/Users/zhaokaijie/.m2/repository/org/springframework/spring-jdbc/5.3.22/spring-jdbc-5.3.22.jar:/Users/zhaokaijie/.m2/repository/org/springframework/spring-tx/5.3.22/spring-tx-5.3.22.jar:/Users/zhaokaijie/.m2/repository/mysql/mysql-connector-java/8.0.24/mysql-connector-java-8.0.24.jar:/Users/zhaokaijie/.m2/repository/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar:/Users/zhaokaijie/.m2/repository/org/springframework/spring-core/5.3.22/spring-core-5.3.22.jar:/Users/zhaokaijie/.m2/repository/org/springframework/spring-jcl/5.3.22/spring-jcl-5.3.22.jar:/Users/zhaokaijie/.m2/repository/org/projectlombok/lombok/1.18.24/lombok-1.18.24.jar com.lyzd.dcms.scms.mock.scmsmock.dao.ClassLoaderTest
启动类加载器
 === > file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/resources.jar
 === > file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/rt.jar
 === > file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/sunrsasign.jar
 === > file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jsse.jar
 === > file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jce.jar
 === > file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/charsets.jar
 === > file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jfr.jar
 === > file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/classes

扩展类加载器Classloader -> sun.misc.Launcher$ExtClassLoader@816f27d
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunec.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/nashorn.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/cldrdata.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/jfxrt.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/dnsns.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/localedata.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/jaccess.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/zipfs.jar

应用类加载器Classloader -> sun.misc.Launcher$AppClassLoader@18b4aac2
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/charsets.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/deploy.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/cldrdata.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/dnsns.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/jaccess.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/jfxrt.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/localedata.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/nashorn.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunec.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/zipfs.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/javaws.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jce.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jfr.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jfxswt.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jsse.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/management-agent.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/plugin.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/resources.jar
 ===> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/rt.jar
 ===> file:/Users/zhaokaijie/IdeaProjects%20/scms-mock/target/classes/
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter-web/2.7.2/spring-boot-starter-web-2.7.2.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter/2.7.2/spring-boot-starter-2.7.2.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot/2.7.2/spring-boot-2.7.2.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.7.2/spring-boot-starter-logging-2.7.2.jar
 ===> file:/Users/zhaokaijie/.m2/repository/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar
 ===> file:/Users/zhaokaijie/.m2/repository/ch/qos/logback/logback-core/1.2.11/logback-core-1.2.11.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.17.2/log4j-to-slf4j-2.17.2.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/apache/logging/log4j/log4j-api/2.17.2/log4j-api-2.17.2.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/slf4j/jul-to-slf4j/1.7.36/jul-to-slf4j-1.7.36.jar
 ===> file:/Users/zhaokaijie/.m2/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/yaml/snakeyaml/1.30/snakeyaml-1.30.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.7.2/spring-boot-starter-json-2.7.2.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.13.3/jackson-databind-2.13.3.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.13.3/jackson-annotations-2.13.3.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.13.3/jackson-core-2.13.3.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.13.3/jackson-datatype-jdk8-2.13.3.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.13.3/jackson-datatype-jsr310-2.13.3.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.13.3/jackson-module-parameter-names-2.13.3.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/2.7.2/spring-boot-starter-tomcat-2.7.2.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.65/tomcat-embed-core-9.0.65.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/9.0.65/tomcat-embed-el-9.0.65.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.65/tomcat-embed-websocket-9.0.65.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/spring-web/5.3.22/spring-web-5.3.22.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/spring-beans/5.3.22/spring-beans-5.3.22.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/spring-webmvc/5.3.22/spring-webmvc-5.3.22.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/spring-aop/5.3.22/spring-aop-5.3.22.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/spring-context/5.3.22/spring-context-5.3.22.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/spring-expression/5.3.22/spring-expression-5.3.22.jar
 ===> file:/Users/zhaokaijie/.m2/repository/io/netty/netty-all/4.1.6.Final/netty-all-4.1.6.Final.jar
 ===> file:/Users/zhaokaijie/.m2/repository/cn/hutool/hutool-all/5.4.6/hutool-all-5.4.6.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/baomidou/mybatis-plus-boot-starter/3.3.1/mybatis-plus-boot-starter-3.3.1.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/baomidou/mybatis-plus/3.3.1/mybatis-plus-3.3.1.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/baomidou/mybatis-plus-extension/3.3.1/mybatis-plus-extension-3.3.1.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/baomidou/mybatis-plus-core/3.3.1/mybatis-plus-core-3.3.1.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/baomidou/mybatis-plus-annotation/3.3.1/mybatis-plus-annotation-3.3.1.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/github/jsqlparser/jsqlparser/3.1/jsqlparser-3.1.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/mybatis/mybatis/3.5.3/mybatis-3.5.3.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/mybatis/mybatis-spring/2.0.3/mybatis-spring-2.0.3.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.7.2/spring-boot-autoconfigure-2.7.2.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/boot/spring-boot-starter-jdbc/2.7.2/spring-boot-starter-jdbc-2.7.2.jar
 ===> file:/Users/zhaokaijie/.m2/repository/com/zaxxer/HikariCP/4.0.3/HikariCP-4.0.3.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/spring-jdbc/5.3.22/spring-jdbc-5.3.22.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/spring-tx/5.3.22/spring-tx-5.3.22.jar
 ===> file:/Users/zhaokaijie/.m2/repository/mysql/mysql-connector-java/8.0.24/mysql-connector-java-8.0.24.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/spring-core/5.3.22/spring-core-5.3.22.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/springframework/spring-jcl/5.3.22/spring-jcl-5.3.22.jar
 ===> file:/Users/zhaokaijie/.m2/repository/org/projectlombok/lombok/1.18.24/lombok-1.18.24.jar
 ===> file:/Applications/IntelliJ%20IDEA.app/Contents/lib/idea_rt.jar

Process finished with exit code 0

自定义类加载器

 public class Hello {
     static {
         System.out.println("Hello Class Initialized!");
     }
 }
 public class HelloClassLoader extends ClassLoader {
     public static void main(String[] args) {
         try {
             new HelloClassLoader().findClass("jvm.Hello").newInstance();
             // 加载并初始化Hello类
              } catch (ClassNotFoundException e) {
             e.printStackTrace();
         } catch (IllegalAccessException e) {
             e.printStackTrace();
         } catch (InstantiationException e) {
             e.printStackTrace();
         }
     }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException{
    String helloBase64 = "yv66vgAAADQAHwoABgARCQASABMIABQKABUAFgcAFwcAGAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQALTGp2bS9IZWxsbzsBAAg8Y2xpbml0PgEAClNvdXJjZUZpbGUBAApIZWxsby5qYXZhDAAHAAgHABkMABoAGwEAGEhlbGxvIENsYXNzIEluaXRpYWxpemVkIQcAHAwAHQAeAQAJanZtL0hlbGxvAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAAAAAAAgABAAcACAABAAkAAAAvAAEAAQAAAAUqtwABsQAAAAIACgAAAAYAAQAAAAMACwAAAAwAAQAAAAUADAANAAAACAAOAAgAAQAJAAAAJQACAAAAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAABgAIAAcAAQAPAAAAAgAQ";
     byte[] bytes = decode(helloBase64);
     return defineClass(name,bytes,0,bytes.length);
  }
public byte[] decode(String base64){
    return Base64.getDecoder().decode(base64);
 }
}

可以初始化hello.java的内容,也相当于对hello.java加密处理

添加引用类的方法

有时候我们在程序已经运行了以后,还是想要再额外的去加载一些jar或类,需要怎么做呢?

简单说就是不使用命令行参数的情况下,怎么用代码来运行时改变加载类的路径和方式。假如说,在 d:/app/jvm 路径下,有我们刚才使用过的Hello.class文件,怎么在代码里能加载这个Hello类呢?

两个办法,一个是前面提到的自定义ClassLoader的方式,还有一个就是直接在当前的应用类加载器里,使用URLClassLoader类的方法addURL,不过这个方法是protected的,需要反射处理一 下,然后又因为程序在启动时并没有显示加载Hello类,所以在添加完了classpath以后,没法直接显式初始化,需要使用Class.forName的方式来拿到已经加载的Hello类Class.forName(“jvm.Hello”)默认会初始化并执行静态代码块)。代码如下:

 import java.lang.reflect.InvocationTargetException; 

 import java.lang.reflect.Method; 

 import java.net.MalformedURLException; 

import java.net.URL; 

 import java.net.URLClassLoader; 



public class JvmAppClassLoaderAddURL { 

public static void main(String[] args) { 

String appPath = "file:/d:/app/"; 

URLClassLoader urlClassLoader = (URLClassLoader) JvmAppClassLoaderAddURL 

try { 

Method addURL = URLClassLoader.class.getDeclaredMethod("addURL" 

addURL.setAccessible(true); 

URL url = new URL(appPath); 

addURL.invoke(urlClassLoader, url); 

Class.forName("jvm.Hello"); // 效果跟Class.forName("jvm.Hello").newInstance()一样 

} catch (Exception e) { 

e.printStackTrace(); 

}

 } 

 } 

执行以下,结果如下:

$ java JvmAppClassLoaderAddURL

Hello Class Initialized!

结果显示Hello类被加载,成功的初始化并执行了其中的代码逻辑。

JVM内存结构

我们先来看看JVM整体的内存概念图:JVM内部使用的Java内存模型, 在逻辑上将内存划分为 线程栈 (thread stacks) 和 堆内存 (heap)两个部分。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接

JVM中,每个正在运行的线程,都有自己的线程栈。 线程栈包含了当前正在执行的方法链/调用链上的所有方法的状态信息。 所以线程栈又被称为“ 方法栈 ”或“ 调用栈 ”(call stack)。 线程在执行代码时,调用栈中的信息会一直在变化。线程栈里面保存了调用链上正在执行的所有方法中的局部变量。 每个线程都只能访问自己的线程栈。 每个线程都不能访问(看不见)其他线程的局部变量。 即使两个线程正在执行完全相同的代码,但每个线程都会在自己的线程栈内创建对应代码中声明的局部变量。 所以每个线程都有一份自己的局部变量本。 所有原生类型的局部变量都存储在线程栈中,因此对其他线程是不可见的。 线程可以将一个原生变量值的副本传给另一个线程,但不能共享原生局部变量本身。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DfDWVjZQ-1671374994120)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20221202155342713.png)]

堆内存中包含了Java代码中创建的所有对象,不管是哪个线程创建的。 其中也涵盖了包装类型(例如 Byte , Integer , Long 等)。不管是创建一个对象并将其赋值给局部变量, 还是赋值给另一个对象的成员变量, 创建的对象都会被保存到堆内存中。下图演示了线程栈上的调用栈和局部变量,以及存储在堆内存中的对象:如果是原生数据类型的局部变量,那么它的内容就全部保留在线程栈上。如果是对象引用,则栈中的局部变量槽位中保存着对象的引用地址,而实际的对象内容保存在堆中。对象的成员变量与对象本身一起存储在堆上, 不管成员变量的类型是原生数值,还是对象引用。类的静态变量则和类定义一样都保存在堆中。

总结一下:方法中使用的原生数据类型和对象引用地址在栈上存储;对象、对象成员 与类定义、静态变量在堆上

堆内存又称为“ 共享堆 ”,堆中的所有对象,可以被所有线程访问, 只要他们能拿到对 象的引用地址。 如果一个线程可以访问某个对象时,也就可以访问该对象的成员变量。如果两个线程同时调用某个对象的同一方法,则它们都可以访问到这个对象的成员变量,但每个线程的局部变量副本是独立的。

示意图如下所示:总结一下:虽然各个线程自己使用的局部变量都在自己的栈上,但是大家可以共享堆上的对象,特别地各个不同线程访问同一个对象实例的基础类型的成员变量,会给每个线程一个变量的副本。\

JMM

目前的JMM规范对应的是 “[JSR­133. Java Memory Model and Thread Specification] (https://jcp.org/en/jsr/detail?id=133)” ,这个规范的部分内容润色之后就成为了《Java 语言规范》的 [$17.4. Memory Model章节(https://docs.oracle.com/javase/specs/jls/se8/html/jls­17.html#jls­17.4)。可以看到,JSR133 的最终版修订时间是在2014年,这是因为之前的Java内存模型有些坑,所以在Java 1.5版本的时候进行了重新设计,并一直沿用到今天。JMM规范明确定义了不同的线程之间,通过哪些方式,在什么时候可以看见其他线程保存到共享变量中的值;以及在必要时,如何对共享变量的访问进行同步。这样的好处是屏蔽各种硬件平台和操作系统之间的内存访问差异,实现Java并发程序真正的跨平台。

随着Java在Web领域的大规模应用,为了充分利用多核的计算能力,多线程编程越来越受欢迎。这时候就出现很多线程安全方面的问题。想要真正掌握并发程序设计,则必须要理解Java内存模型。可以说,我们在JVM内存结构中学过的 堆内存 、 栈内存等知识,以及Java中的同步、锁、线程等等术语都和JMM有非常大的关系。

**总结:**目的是解决java并非的问题

JVM参数

用法: java [-options] class [args...]
           (执行类)
   或  java [-options] -jar jarfile [args...]
           (执行 jar 文件)
其中选项包括:
    -d32	  使用 32 位数据模型 (如果可用)
    -d64	  使用 64 位数据模型 (如果可用)
    -server	  选择 "server" VM
                  默认 VM 是 server,
                  因为您是在服务器类计算机上运行。


    -cp <目录和 zip/jar 文件的类搜索路径>
    -classpath <目录和 zip/jar 文件的类搜索路径>: 分隔的目录, JAR 档案
                  和 ZIP 档案列表, 用于搜索类文件。
    -D<名称>=<>
                  设置系统属性
    -verbose:[class|gc|jni]
                  启用详细输出
    -version      输出产品版本并退出
    -version:<>
                  警告: 此功能已过时, 将在
                  未来发行版中删除。
                  需要指定的版本才能运行
    -showversion  输出产品版本并继续
    -jre-restrict-search | -no-jre-restrict-search
                  警告: 此功能已过时, 将在
                  未来发行版中删除。
                  在版本搜索中包括/排除用户专用 JRE
    -? -help      输出此帮助消息
    -X            输出非标准选项的帮助
    -ea[:<packagename>...|:<classname>]
    -enableassertions[:<packagename>...|:<classname>]
                  按指定的粒度启用断言
    -da[:<packagename>...|:<classname>]
    -disableassertions[:<packagename>...|:<classname>]
                  禁用具有指定粒度的断言
    -esa | -enablesystemassertions
                  启用系统断言
    -dsa | -disablesystemassertions
                  禁用系统断言
    -agentlib:<libname>[=<选项>]
                  加载本机代理库 <libname>, 例如 -agentlib:hprof
                  另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
    -agentpath:<pathname>[=<选项>]
                  按完整路径名加载本机代理库
    -javaagent:<jarpath>[=<选项>]
                  加载 Java 编程语言代理, 请参阅 java.lang.instrument
    -splash:<imagepath>
                  使用指定的图像显示启动屏幕
有关详细信息, 请参阅 http://www.oracle.com/technetwork/java/javase/documentation/index.html。

JVM 启动参数–运行模式

1.-server:设置 JVM 使用 server 模式,特点是启动速度比较慢,但运行时性能和内存管理效率很高,适用于生产环境。在具有 64 位能力的 JDK 环境下将默认启用该模式,而忽略 -client参数

  1. -client:JDK1.7 之前在32位的 x86 机器上的默认值是 -client 选项。设置 JVM 使用 client 模式,特点是启动速度比较快,但运行时性能和内存管理效率不高,通常用于客户端应用程序或者 PC 应用开发和调试。
  2. -Xint:在解释模式(interpreted mode)下运行,-Xint 标记会强制 JVM 解释执行所有的字节码,这当然会降低运行速度,通常低10倍或更多。
  3. -Xcomp:-Xcomp 参数与-Xint 正好相反,JVM 在第一次使用时会把所有的字节码编译成本地代码,从而带来最大程度的优化。【注意预热】
  4. -Xmixed:-Xmixed 是混合模式,将解释模式和编译模式进行混合使用,有 JVM 自己决定,这是 JVM 的默认模式,也是推荐模式。 我们使用 iava -version 可以看到 mixed mode 等信息。常用的代码编译成字节码,不常用的代码使用机器码的混合模式

JVM 启动参数–对内存

-Xmx, 指定最大堆内存。 如 -Xmx4g。这只是限制了 Heap 部分的最大值为4g。这个内存不包括栈内存,也不包括堆外使用的内存。
-Xms, 指定堆内存空间的初始大小。 如 -Xms4g。而且指定的内存大小,并不是操作系统实际分配的初始值,而是GC先规划好,用到才分配。 专用服务器上需要保持 -Xms 和 -Xmx 一致,否则应用刚启动可能就有好几个 FullGC。当两者配置不一致时,堆内存扩容可能会导致性能抖动。
-Xmn, 等价于 -XX:NewSize,(Young)使用 G1 垃圾收集器 不应该 设置该选项,在其他的某些业务场景下可以设置。官方建议设置为 -Xmx 的 1/2~¼。 默认young:old = 1:2 也就是说 默认设置是1/3
-XX:MaxPermSize=size, 这是 JDK1.7 之前使用的。Java8 默认允许的 Meta空间无限大,此参数无效。
-XX:MaxMetaspaceSize=size,Java8 默认不限制 Meta 空间,一般不允许设置该选项。
-XX:MaxDirectMemorySize=size,系统可以使用的最大堆外内存,这个参数跟-Dsun.nio.MaxDirectMemorySize 效果相同。不受GC管理
-Xss, 设置每个线程栈的字节数,影响栈的深度。 例如 -Xss1m 指定线程栈为 1MB,与-XX:ThreadStackSize=1m 等价。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LqAYaTBL-1671374994121)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20221211102109401.png)]

Xmx和Xms一开始配置一样大,合理的配置可以减少full GC的次数减少停顿

Xmx配置为60%-80%

GC相关参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QBvQbOjt-1671374994121)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20221218092911605.png)]

诊断相关参数

配置内存快照,用于分析内存的状况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W2eNoUn2-1671374994121)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20221218093324826.png)]

出现问题的时候调用Debug运行当前程序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aFvC9wjS-1671374994121)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20221218093514951.png)]

不改变原有的jar、class的情况下用于在类加载的时候做增强

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值