JVMday03、类文件结构 、字节码指令 、多态的原理、 异常、 synchronized代码块底层原理

类文件结构

查看二进制字节码的命令(linux)
在这里插入图片描述

类文件结构
在这里插入图片描述

1、魔术(magic)

在这里插入图片描述

不同的文件有自己的魔术信息,魔术就是标识这个文件属于什么类型。而java文件的魔术就是cafebabe,占4个字节(u4)。

2、版本
在这里插入图片描述

minor_version 小版本:00 00 (u2)
major_version 主版本:00 34 (u2)
00 34 的十进制就是52,代表的是jdk1.8

3、常量池(constant_pool)

常量池中包括各种信息:方法的信息,成员变量的信息,类的信息,构造器的信息,父类的信息。

常量池中的17中数据类型(详细)
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

<init>就是构造方法
utf-8后面2字节代表长度,代指要读几个字节。

在这里插入图片描述

4、访问标识(access_flags)

00 21 代表 00 01 + 00 20 ,表示这个类是public的,占2个字节

在这里插入图片描述

5、本类全限定名(this_class)

根据常量池查找。
Java类包的定名:com.halulu.test.Hello,从最原始最上层的地方援引到具体的对象,这就是全限定名了。
占2个字节

6、父类的全限定名(super_class)

根据常量池查找。
占2个字节

7、接口数量(interface)

占2个字节

8、成员变量(fields)

flelds_count:成员变量的数量,占2个字节

在这里插入图片描述

9、方法(methods)

method_count :方法数量,占2个字节

10、附加属性(attributes)


字节码指令

工具

javap -v xxx.class

aload 加载变量
getstatic 从运行时常量池中找到成员变量(堆)的引用。(并不会把成员变量直接放进栈中,而是堆中成员变量的引用放入栈中)
putstatic 将栈中的数值赋值给常量池中成员变量
bipush 将一个byte压入操作数栈中(其长度会补齐4个字节)
sipush 讲一个short压入操作数栈中(其长度会补齐4个字节)
ldc 将一个int 压入操作数栈中(找到常量池中的属性,然后压入操作数栈)
idc2_w 将一个long压入操作数栈中(分2次压入,因为long是8字节)
athrow 抛出异常

monitorenter 加锁
monitorexit 解锁

invokespecial 预备调用构造方法(静态绑定,直接确定方法)
invokevirtual 预备调用成员方法,然后会分配一个新的栈帧(动态绑定,普通方法可能会发生方法重写,所以在编译期间不能确定调用何种方法,需要在运行的时候才能确定)(vtable中)
invokerstatic 调用静态方法(静态绑定,直接确定方法)

new 在堆空间分配内存,然后把对象的引用放入操作数栈
dup 把栈顶的地址进行复制
pop出栈

在这里插入图片描述

istore 1 代表把栈顶中的数值放到槽位1中(slot)
iload 1 代表把槽位1中的值读取到操作数栈上
iadd 代表加法运算
iinc 直接在局部变量槽位slot上运行(iinc 1,1 第一个数组代表对哪个槽位自增,第二数代表自增多少)
小的数字和字节码指令存放在一起,超过short范围的数字存入了常量池

条件判断指令
在这里插入图片描述

byte、short、char会自动补齐4位字节,按int进行条件判断

循环控制指令

iconst_0 代表常量0
int 取值 0~5 时,JVM采用 iconst_0、iconst_1、iconst_2、iconst_3、iconst_4、iconst_5指令将常量压入栈中;
goto 2 代表跳到第2行代码
while和for循环的字节码指令是一样的

short类型以下的数字是跟字节码指令存储在一起的,并不会放在常量池中,short类型之上的数字才会放在常量池中,常量池随着类的加载会放入运行时常量池中。

从字节码角度分析a++ ,++a
在这里插入图片描述

a++ 和 ++ a的区别在于先执行iload 还是先执行 iinc.

在这里插入图片描述

istore_1 存放a
istore_2 存放b

在这里插入图片描述

案例:a = a++

    public static void main(String[] args) {
        int a = 0;
        int i = 0;
        int b = 0;
        while (i < 5){
            a = a++; //0  ,iload , iinc , istore
            b = ++b; //5 , iinc , iload ,istore   
            i++;
        }
        System.out.println(a);
        System.out.println(b);
    }

在这里插入图片描述

1、a的初始值是0,
2、iload_1将a加载到栈中,此时栈中的值为0,
3、iinc 1,1 槽位中的a+1 变为1 ,此时栈中的值依旧为0,
4、istore_1 将栈中的0顶替槽位slot中的1,此时槽位中的a就变为0了


静态的a++ 和 a–
在这里插入图片描述

与前面不同的是,静态的a++和a–是在操作数栈上自增自减的,而非静态的自增和自减是在槽上进行,但所得的结果一直。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


构造器的原理

public class Demo2 {
    static int a = 10;
    static {
        a = 20;
    }
    static {
        a = 30;
    }

    public static void main(String[] args) {
        System.out.println(a); // 30
    }
}

在这里插入图片描述

这三个static在编译阶段会合并成一个<cinit>方法,顺序是从上往下


在这里插入图片描述

编译器会按从上至下的顺序,收集所有 {} 代码块和成员变量赋值的代码,形成新的构造方法<init>,但原始构造方法内的代码总是在最后。

多态的原理

工具

1、jps获取进程
2、java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB

当执行invokevirtual指令时(多态)
1、通过栈帧中的对象引用找到对象
2、分析对象头,找到对象的实际class
3、class结构中有vtable(虚方法表),它在类加载的链接阶段就已经按照方法重写的规则生成
4、查表可以的得到多态方法的具体地址
5、执行方法的字节码

异常

1、单个Catch块
在这里插入图片描述

exception table 异常表

在这里插入图片描述

代码从第2行运行到第4行的时候,会跟type中的exception进行匹配,如果匹配通过,就会进入第8行,也就是catch块,如果不通过,就跳过(error或者throwable与exception是匹配不上的)。

2、多个catch块
在这里插入图片描述

在这里插入图片描述

过程跟单个catch块一致,会依次进行匹配。

3、multi-catch块
在这里插入图片描述

在这里插入图片描述

4、finally块

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1、如果异常是exctption,那么会把finally块中的字节码放在try块或者catch块的后面,注意是在return块之前。(保证一定会被执行)
2、如果异常是throwable或者error(不会与exception匹配),try块或者Catch块会与any进行匹配,然后通过,运行finally块(保证一定会执行)
3、try-catch-finally会被分为3个分支:try分支,catch分支,catch匹配不到的分支。然后finally块中的代码会被复制3份,分别放入这3个分支中,保证finally块一定会被执行。

案例1:finally出现了return
在这里插入图片描述

在这里插入图片描述

案例2:finally中的return会吞掉athrow(不会抛出异常)

    public static void main(String[] args) {
        int result = test();
        System.out.println(result);
    }

    public static int test() {
        try {
            int i = 1/0;
            return 10;
        } catch (Exception e){
            return 30;
        }finally {
            return 20;
        }
    }

finally中的return会吞掉异常athrow,会导致代码运行并不会抛出异常,尽量不在finally中使用return。

案例3

    public static void main(String[] args) {
        int result = test();
        System.out.println(result);
    }

    public static int test() {
        int i = 10;
        try {
            return i;   // 10 , 返回值固定
       } finally {
            i = 20;  //槽位的数值变化
        }
    }

在这里插入图片描述

返回值固定,这个时候finally仅仅只是改变了槽位上的值,并没有改变栈顶上的值,而return返回的是栈顶上的值。

synchronized代码块底层原理

    public static void main(String[] args) {
        Object lock = new Object();
        synchronized (lock) {
            System.out.println("ok");
        }
    }

在这里插入图片描述

1、方法级别的synchronized不会再字节码指令中体现。
2、monitorenter 与 monitorexit 加载到同个类型的锁对象才会通过
3、如果抛出异常,也会确保monitorexit 加载到同一个类型得到锁对象(确保一定会被解锁,然后抛出异常)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的别和位置,是计算机视觉领域的核心问题之一。由于各物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体别(目标分)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个别的概率(首先得到别概率,经过Softmax可得到别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分,并根据分结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测别匹配真实值(Ground truth)的别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

halulu.me

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

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

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

打赏作者

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

抵扣说明:

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

余额充值