JVM讲解

JVM讲解

java是跨平台的语言

首先大家学Java都知道Java是跨平台的语言,一次编译到处运行。那么为什么Java能跨平台运行呢?其实就是我们今天要学习的jvm。我们不同的平台会安装不同的jdk,jdk当中又有不同的jvm虚拟机,然后不同的虚拟机可以将相同的字节码编译成不同的机器码供不同平台运行。看下图:

请添加图片描述

下面我们再来看看我们的JVM内存模型图

请添加图片描述

其中蓝色区域是线程独有的,黄色区域是线程共享的。

上图可以看到,我们的JVM里面会有类装载子系统,也可说为类加载器,那么我们类加载器的作用是什么呢?

  • 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。

双亲委派机制

请添加图片描述

从上图中我们就更容易理解了,当一个.class这样的文件要被加载时。不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。如果没有,就会向上委托给父加载器,然后调用父加载器的loadClass方法。父类中同理也会先检查自己是否已经加载过,如果没有再往上。注意这个类似递归的过程,直到到达Bootstrap classLoader之前,都是在检查是否加载过,并不会选择自己去加载。直到BootstrapClassLoader,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。

本地方法栈(Native Method Stack)

本地方法栈是用来做什么的?首先我们得聊聊native关键字;

native关键字

//对Thread,start();方法源码追踪
 public synchronized void start() {
        if (threadStatus != 0)//判断线程是否是新生的
            throw new IllegalThreadStateException();
        group.add(this); //将其添加到线程组里面

        boolean started = false; //线程没有启动
        try {
            start0(); // 调用start0
            started = true;//线程启动
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
             
            }
        }
    }

    //思考:为什么可以在非抽象类里面写这样的一串代码?
    private native void start0(); 

因为凡是带了native关键字的 ,表示JAVA达不到的范围,它就会去调用底层C语言的库。

会进入本地方法栈,去调用本地方法接口 (JNI)

JNI的作用:扩展JAVA的使用,融合不同的编程语言为JAVA所用。

下面回到我们的本地方法栈的讲解。

在早期JAVA诞生的时候,C,C++横行,所以JAVA必须要有可以调用它们的程序,所以在内存中专门开辟了本地方法栈(Native Method Stack)用来登记native方法。

最后执行的时候通过JNI去加载本地方法库中的方法

程序计数器

程序计数器也就是pc寄存器:Program Counter Register

​ 每个线程都有一个程序计数器,是线程私有的,就是一个指针,指令方法区中的方法字节码(用来存储指向下一条指令的地址,也就是即将要执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。

(9)面试问题
① 使用PC寄存器存储字节码指令地址有什么用?
答:CPU会不停的切换各个线程,通过PC寄存器记录的地址值可以知道从哪里继续开始执行。
② PC寄存器为什么会被设定为线程私有?
答:为了能够准确的记录各个线程正在执行的当前字节码指令地址,最好的办法就是为每一个线程都分配一个PC寄存器。

方法区

Method Area 方法区

方法区是被所有线程共享的,所有字段和方法字节码以及一些特殊的方法,如构造函数,接口代码也在此处定义,简单说所有的定义方法的信息都保存在该区域,属于共享区域

静态变量(static),常量(final),类信息(构造方法,接口定义),运行时常量池。实例变量存在堆内存中与方法区无关

java自带的调优工具

jvisualvm

主要是存放对象的以及数组的。数组和对象永远不能在栈中,栈中保存的数组和对象的引用,引用指向堆中的数组和对象。

是GC垃圾收集器的重点区域。

垃圾收集:

堆空间分为:年轻代,老年代,元空间

年轻代又分为了Eden区和S0(from),S1(to)。默认比列8:1:1

Minor Gc 触发条件:Eden区满了会触发,

栈又被称为Java虚拟机栈,是方法执行的时候的内存模型, 每个方法被执行的时候,JVM都会同步创建一个栈帧用于存储局部变量表操作数栈动态连接方法出口等信息。

  • 局部变量表:存放的是方法内的局部变量,如果是基本数据类型,直接存放。如果是对象类型,存放的是对象的指针。
  • 操作数栈: 当一个方法刚刚开始执行时,其操作数栈是空的,随着方法执行和字节码指令的执行,会从局部变量表或对象实例的字段中复制常量或变量写入到操作数栈,再随着计算的进行将栈中元素出栈到局部变量表或者返回给方法调用者,也就是出栈/入栈操作。一个完整的方法执行期间往往包含多个这样出栈/入栈的过程。
  • 动态链接:动态连接就是在编译时是不确定的,比如Java的多态,可能有多个实现类,在编译时期可能是不知道最终要调用哪个实现类的方法的,只能在程序运行期间根据实际的类型绑定相关的方法,这个就是动态连接。
    这样出栈/入栈的过程。
  • 动态链接:动态连接就是在编译时是不确定的,比如Java的多态,可能有多个实现类,在编译时期可能是不知道最终要调用哪个实现类的方法的,只能在程序运行期间根据实际的类型绑定相关的方法,这个就是动态连接。
  • 方法出口:当一个方法执行完成后的返回消息,也有可能是异常信息。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

末、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值