jvm基本结构


jvm由三个子系统构成:

  • 类加载子系统
  • 运行时数据区(内存结构)
  • 执行引擎
    在这里插入图片描述

一、类加载子系统

在这里插入图片描述
主要用于将类class文件加载到内存中,通过类加载器(classloader)进行加载。

以下为类的加载过程:

加载–>验证–>准备–>解析–>初始化–>使用–>卸载
在这里插入图片描述
类的生命周期

    加载:查找并加载类的二进制流,将class文件从磁盘加载到内存中
    验证:验证类信息是准确的,符合jvm的规范
    准备:为类的静态变量进行初始化,分配空间并赋予初始值
        例如存在一个类静态变量int i=10;此处只是分配内存和赋予默认值,所以此时int i=0 占4字节;
    解析:类加载器装入类所引用的其他所有的类(静态链接)
    初始化:jvm对类进行初始化,并给静态变量赋予准确的值
        执行静态代码块,将准备阶段静态变量赋于准确的值,int i = 10
类加载器
public class test01 {

    public static void main(String[] args) {
        test01 test01 = new test01();
        test01.test();
    }

    public void test(){
        ClassLoader classLoader = this.getClass().getClassLoader();
        // sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println(classLoader);
        // sun.misc.Launcher$ExtClassLoader@61bbe9ba
        System.out.println(classLoader.getParent());
        // null bootstrapClassLoader(c语言写的)
        System.out.println(classLoader.getParent().getParent());

    }
}

在这里插入图片描述
以上不是继承关系,只是父类加载器
bootstrapClassLoader(c语言写的):主要加载(jdk/jre/lib下 jar包)
ExtClassLoader:主要加载(jdk/jre/lib/ext下 jar包)
AppClassLoader:主要加载 自己定义的类(类路径下的)
用户自定义类加载器:可以通过流、网络、数据库等渠道加载

双亲委派机制

双亲委派
如果一个类收到了加载请求,它不会直接加载,首先会委托父加载器进行加载(依次向上请求加载),若无法加载才会交给子类进行加载
:AppClassLoader收到加载请求,会委托extclassloader加载,extclassloader会交由bootstrapClassLoader加载,
若bootstrapClassLoader不能加载,则子类加载起(extclassloader)进行加载,若子类也无法加载才会交由(AppClassLoader)进行加载
优点:避免重复加载 + 避免核心类篡改
采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java
API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。
tomcat打破了双亲委派机制:可以通过自定义的类加载机制打破双亲委派
为什么打破:tomcat为了隔离war包
tomcat中若存在多个war包时,项目启动时会加载到同一个jvm中,若多个war中存在同一个类,双亲委派机制只会加载一个类,但是两个类是用于不同类中的,所以tomcat自定义类加载器来打破双亲委派机制

全盘负责机制

当一个classloader加载一个类的时候,除非显示的使用另一个classloader,给类所依赖的和所引用的类也由这个classloader加载

二、运行时数据区(内存结构)

在这里插入图片描述
包含了方法区(jdk1.8后改名为元空间)、堆、栈、本地方法栈、程序计数器
堆、方法区是共享的
栈、本地方法栈、程序计数器:线程间不共享的,属于jvm自行管理,随线程启动而创建,线程结束后jvm自动回收

线程
在这里插入图片描述

public class test {
    public test() {
    }

    public int compute() {
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }

    public static void main(String[] args) {
        test test = new test();
        int i = test.compute();
        System.out.println(i);
    }
}
# 查看反汇编语言
javap -c test.class
Compiled from "test.java"
public class com.guocoffee.base.test04.test {
  public com.guocoffee.base.test04.test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public int compute();
    // 0: 1: 序号可以认为是程序计数器,记录的是将要执行的序号 
    // 例如:目前运行到序号2,程序计数器中保存的是3
    // 为什么是将要执行的序号:确保线程间切换时运行正常
    // 若存在不连续的序号时:属于jvm的优化
    Code:
       0: iconst_1      // iconst:将int类型常量放入操作栈中 1代表第一个常量   也就是将a放进操作数栈
       1: istore_1      // istore:存储一个int类型放进局部变量表
       2: iconst_2      // 将b放进操作数栈
       3: istore_2      // 存储b到局部变量表
       4: iload_1       // 加载第一个变量放进操作数栈
       5: iload_2       // 加载第二个变量放进操作数栈
       6: iadd          // int类型执行加法操作
                        // 第一个变量和第二个变量做出栈操作进行运算,然后再压回栈中
       7: bipush        10  // 从常量池中获取10压栈
       9: imul          // 执行乘法操作
      10: istore_3      // 将结果存储到局部变量表c
      11: iload_3       // 加载第三个变量
      12: ireturn       // 直接return回去?返回给谁?栈帧中有保存方法出口

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/guocoffee/base/test04/test
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method test01:()I
      12: istore_2
      13: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      16: iload_2
      17: invokevirtual #6                  // Method java/io/PrintStream.println:(I)V
      20: return
}
本地方法栈

不属于Java,属于c


// new Thread().start(); start底层调用的就是本地方法
// 使用native修饰的
private native void start0();
方法区(元空间、永久带、持久带)

静态变量、常量、类信息(构造方法/接口定义)、运行时常量池均保存在方法区。

在这里插入图片描述

分为新生代+老年代(1:2),新生代分为(伊甸园和两个幸存区)(8:1:1)。
yongGC/minorGC(回收新生代)
fullGC/majorGC(收所有区域)
大对象若伊甸园放不下会直接放在老年代,老年代保存一些大对象及存活比较久的对象。
新出生的对象一般保存在伊甸园区,当伊甸园满之后将会发生yongGC/minorGC(回收新生代)
fullGC/majorGC 回收所有区域
stw:stop the world:yongGC和fullGC都会产生stw,yongGC的stw比较短暂快速,fullGC停顿时间比较长

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值