4. JVM运行时数据区与JVM指令集

1 运行时数据区 Run-time data areas
  1. Java虚拟机执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域
    在这里插入图片描述
1.1 程序计数器 Program Counter
  1. 每个线程一个
  2. 用于存放指令的位置
  3. 虚拟机的运行类似如下循环
while(not end){
	取PC中的位置,找到对应位置的指令;
	执行该指令;
	PC++;
}
1.2 堆 Heap
1.3 本地方法栈 native method stacks

本地方法所使用的栈

1.4 直接内存 Direct Memory
  1. NIO使用,可以直接访问操作系统内存
  2. 老版本Java读取网络资源时,先将网络资源读到内核空间,当jvm使用时,从内核拷贝到jvm内存中,效率低
  3. NIO可以使用直接内存,省略了拷贝的步骤,直接访问内核空间,也就是所谓的0拷贝(zero copy)
1.5 方法区 method area
  1. 存放运行时常量池run-time constant pool
    1. 编译时产生的constant pool table,到运行时,就放在这里
    2. 存放class文件中的符号引用,以及这些符号引用转为的直接引用
    3. 字符串常量1.7在method area,1.8以后在堆中
  2. 永久代(permspace)(1.7)/ 元数据区(Metaspace)(1.8) ,是hotspot的不同jdk版本,对method area的具体实现
    1. 永久代启动时必须指定大小限制 ,元数据可以设置,也可以不设置,仅受限于物理内存
    2. fgc无法对永久代进行回收,但可以对metaspace进行回收
  3. 注意Class对象存放于堆中,Class文件的字节码,存放于method area
1.6 栈 JVM stacks
  1. 每个线程对应一个栈,每个方法对应一个栈针(frame),栈中存放着一个个栈帧
  2. 栈帧:存放数据,包含以下内容
    1. 局部变量表(local variable table):存放当前栈帧中所用到的局部变量,栈帧弹出后,局部变量表消失,局部变量的名,记录在constant_pool
      1. 对于非static方法,局部变量表中第一个局部变量是this,这也是为什么我们可以直接使用this关键字
      2. 对于main方法,局部变量表中第一个局部变量是args
        在这里插入图片描述
    2. 操作数栈(operand stacks):理解为存放操作数的栈,方法执行的过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈和入栈操作
    3. 动态连接(dynamic linking):字节码中的方法调用指令,会以常量池指向方法的符号引用作为参数,这些符号引用一部分在类加载时,转为直接引用,称为静态连接,另一部分运行时被转化为直接引用,称为动态链接
    4. 方法返回地址(return address):方法a调用方法b,b方法的return address,记录b方法返回值放在哪,以及b方法执行完后,应返回a方法的什么位置继续执行
2 JVM指令集
2.1 ++i与i++
  1. ++i
public class TestIPulsPlus {
    public static void main(String[] args) {
        int i = 8;
//        i = i++;
        i = ++i;
        System.out.println(i);
    }
}

在这里插入图片描述

//第一列表示指令序号,第二列为指令
//使用jclasslib时,指令具体含义可以直接单击指令,会进入oracle网页的官方介绍,也可以在jvm虚拟机规范文档中查到,jvms13中6.5节
//放入一个byte值自动扩展为int,然后压栈
 0 bipush 8
//将栈顶的int数出栈,放到局部变量表下标为1的局部变量中,也就是i
 2 istore_1
//将局部变量表中,下标为1的int类型的局部变量,增加1,此时局部变量表中,i值为9,操作数栈中无元素
 3 iinc 1 by 1
//将局部变量表中,下标为1的局部变量压栈
 6 iload_1
 7 istore_1
 8 getstatic #2 <java/lang/System.out>
11 iload_1
12 invokevirtual #3 <java/io/PrintStream.println>
15 return
  1. i++
    在这里插入图片描述
//注意修改java文件后,需要重新执行一次,class才变,在jclasslib中,也要刷新,指令才会变
 0 bipush 8
 2 istore_1
 3 iload_1
//只有此处变换了位置,这就是为什么i++当时指令时,值不变,下一条指令时,其值才变化
 4 iinc 1 by 1
 7 istore_1
 8 getstatic #2 <java/lang/System.out>
11 iload_1
12 invokevirtual #3 <java/io/PrintStream.println>
15 return
2.2 设计指令集的方式
  1. 基于栈的指令集:JVM采用的就是这种,不断压栈、出栈
  2. 基于寄存器的指令集:例如汇编语言,复杂,但快
    1. 硬件层面最后都是基于寄存器的
2.3 Hello_03
  1. 代码
public class Hello_03 {
    public static void main(String[] args) {
        Hello_03 h = new Hello_03();
        int i = h.m1();
    }

    public int m1() {
        return 100;
    }
}
  1. 线程栈中情况
    在这里插入图片描述
    1. 只有一个线程,是主线程
    2. 主线程栈中存在两个栈帧,一个是main方法对应的栈帧,另一个是m1方法对应的栈帧
    3. 执行到h.m1时,m1方法的栈帧才进入主线程栈中
    4. m1方法执行完后,其栈帧会弹出,此时main方法才能继续执行
    5. 线程的栈存满了无法再放入栈帧时,报错stack over flow
  2. 指令集
//1. main方法
//创建对象,并赋默认值,然后将该对象地址压栈
 0 new #2 <Hello_03>
//将操作数栈中栈顶的元素复制一个并压栈,此时相当于操作数栈中,存放了两份Hello_03对象的地址
 3 dup
//栈顶元素出栈,并调用其inti方法,也就是构造函数,这也是为什么dup需要复制一份对象地址的原因,因为调用构造方法时,会用掉一个
 4 invokespecial #3 <Hello_03.<init>>
 7 astore_1
 8 aload_1
//#4表示指向常量池中的第四个常量,这个常量是一个符号引用,表示要执行的方法m1
 9 invokevirtual #4 <Hello_03.m1>
	//2. m1方法。由于调用了m1方法,此时m1栈帧进入线程栈
	0 bipush 100
	2 ireturn
12 istore_2
13 return
2.4 Hello_04
  1. 代码
public class Hello_04 {
    public static void main(String[] args) {
        Hello_04 h = new Hello_04();
        int i = h.m(3);
    }

    public int m(int n) {
        if(n == 1) return 1;
        return n * m(n-1);
    }
}
  1. 指令集
//main方法
 0 new #2 <Hello_04>
 3 dup
 4 invokespecial #3 <Hello_04.<init>>
 7 astore_1
 8 aload_1
//将3这个常量值压栈
 9 iconst_3
10 invokevirtual #4 <Hello_04.m>
	//2. m方法
	//每次递归都创建一个新的栈帧,每个栈帧都叫m,只不过参数不同
	 0 iload_1
	 1 iconst_1
	 //cmp:compare,ne:not equal如果栈顶的两个int元素不相等,跳转至第7号指令,否则跳转到5号指令
	 //指令码编号跨越,是因为某个指令,占的字节数过大,将后面的编号的字节也占用了
	 2 if_icmpne 7 (+5)
	 5 iconst_1
	 6 ireturn
	 7 iload_1
	 8 aload_0
	 9 iload_1
	10 iconst_1
	//两个int元素出栈,相减后,结果入栈
	11 isub
	12 invokevirtual #4 <Hello_04.m>
		//3. m方法,第二次调用
		0 iload_1
	 	1 iconst_1
	 	......
	//两个int元素出栈,相乘后,结果入栈
	15 imul
	16 ireturn
13 istore_2
14 return
2.5 invoke指令
  1. invokestatic:调用了一个static方法
  2. invokevirtual:调用普通方法,自带多态功能,就是说栈中存的是哪个对象的地址,就会调用哪个对象的方法,所以父类引用指向子类,最后会调用子类的方法
  3. invokeinterface:接口的引用,调用方法
  4. invokespecial:调用可以直接定位的方法
    1. 可以直接定位:虚拟机不需要看这个该引用所指向的对象,直接看该引用本身是什么类型,就知道调用哪个方法,不会有多态的问题
    2. 例如:private方法,构造方法,注意final方法不是invokespecial,是invokevirtual
  5. invokedynamic:lambda表达式、反射,或其他动态语言
    1. 动态语言:可以动态产生class的语言,例如:scala、kotlin、cglib、asm
    2. lambda表达式调用时,相当于产生了匿名内部类,这个匿名内部类的class文件也会被加载到内存中
public class T05_InvokeDynamic {
    public static void main(String[] args) {
        I i = C::n;
        I i2 = C::n;
        I i3 = C::n;
        I i4 = () -> {
            C.n();
        };
        I i5 = new I(){
            @Override
            public void m() {
                C.n();
            }
        };
        System.out.println(i.getClass());
        System.out.println(i2.getClass());
        System.out.println(i3.getClass());
        System.out.println(i5.getClass());
        //由于每次使用lambda表达式,都相当于创建了一个匿名内部类,这个匿名内部类的字节码1.7以前,都存在于Perm Space,无法被回收
        //循环使用,导致永久代内存增加,甚至内存溢出
        //for(;;) {I j = C::n;} //MethodArea <1.8 Perm Space (FGC不回收)
    }

    @FunctionalInterface
    public interface I {
        void m();
    }

    public static class C {
        static void n() {
            System.out.println("hello");
        }
    }
}

2.6 其他

在这里插入图片描述

  1. iadd:连续出栈两个int类型的数,将相加后的结果压栈
  2. <clinit>:class initialize,静态的语句块,没有显示的调用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值