JVM执行引擎及基于JVM的对象的实例化过程

导读:本篇文章讲解 JVM执行引擎及基于JVM的对象的实例化过程,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录


在介绍JVM执行引擎前我们先了解一下JVM的整体结构:

总体分为三个部分:类加载子系统(Class Loader Subsystem)、运行时数据区(Runtime Data Area)、执行引擎(Execution Engine)JVM执行引擎及基于JVM的对象的实例化过程

java程序执行过程:java程序经过编译后产生字节码文件(Class Files),字节码文件通过类加载器的(加载、链接、初始化)步骤加载进内存,然后执行引擎通过和运行时数据区的交互解释并执行文件。

类加载过程可详见博文:

运行时数据区可详见博文:

一、执行引擎 

【概述】

执行引擎是Java虚拟机核心的组成部分之一。“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而虚拟机的执行引擎则是由软件自行实现的,因此可以不受物理条件制约地定制指令集与执行引擎地结构体系,能够执行那些不被硬件直接支持地指令集格式。

要想了解执行引擎是用来做什么的,我们先来看一看JVM虚拟机想要做什么?

        JVM的主要任务是负责装载字节码到其内部,但字节码并不能够直接运行在操作系统之上,因为字节码指令并非等价于本地机器指令,它内部包含的仅仅只是一些能够被JVM所识别的字节码指令、符号表,以及其他的辅助信息。         那么,如果想要让一个Java程序运行起来,执行引擎(Execution Engine)的任务就是将字节码指令解释/编译为对应平台上的本地机器指令才可以(这也是Java跨平台特性的原因)。简单来说,JVM中的执行引擎充当了将高级语言翻译为机器语言的译者。

【执行引擎的结构】

执行引擎包括三部分:解释器、JIT编译器(即时编译器)、垃圾回收器

JVM执行引擎及基于JVM的对象的实例化过程

【执行引擎工作过程】

JVM执行引擎及基于JVM的对象的实例化过程

 执行引擎就是根据PC寄存器中的下一条指令的地址取得相应的指令,然后执行一条条的字节码指令,从而完成栈中一系列的操作(入栈、出栈)。

JVM执行引擎及基于JVM的对象的实例化过程 从外观上看,所有的Java虚拟机的执行引擎的输入、输出都是一致的:输入的是字节码二进制流,处理过程是字节码解析执行的等效过程,输出的是执行结果。

【解释执行和JIT即时编译】

下图是Java代码编译和执行的过程: 橙色是java程序翻译成字节码文件的过程(也称 前端编译),与虚拟机无关。 蓝色部分是JVM虚拟机将字节码文件编译成目标代码的过程(也称后端编译或JIT即时编译)。 绿色部分是JVM虚拟机解释执行字节码文件的过程。 

JVM执行引擎及基于JVM的对象的实例化过程

 解释执行需要通过解释器完成,JIT即时编译需要通过JIT编译器完成。那什么是解释器?什么是JIT编译器呢?

  • 解释器:当Java虚拟机启动时会根据预定义的规范对字节码采用逐行解释的方式执行,将每条字节码文件中的内容“翻译”为对应平台的本地机器指令执行。
  • JIT编译器:就是虚拟机将源代码直接编译成本地和本地机器平台相关的机器语言。

 JVM执行引擎及基于JVM的对象的实例化过程

JVM执行引擎及基于JVM的对象的实例化过程

对于HotSpot VM是目前市面上高性能虚拟机代表作之一。它采用解释器与即时编译器并存的 架构。在Java虚拟机运行时,解释器和即时编译器能够相互协作,各自取长补短,尽力去选择最合适的方式来权衡编译本地代码的时间和直接解释执行代码的时间。

JVM执行引擎及基于JVM的对象的实例化过程

对于HotSpot JVM来说,会随着程序运行时间的推移,即时编译器逐渐发挥作用,根据热点探测功能,将有价值的字节码编译为本地机器指令,以换取更高的程序执行效率。

JVM执行引擎及基于JVM的对象的实例化过程

JVM执行引擎及基于JVM的对象的实例化过程

二、对象的实例化过程

【对象创建的常见方式】

  • new(变形:Xxx的静态方法、XxxBuilder/XxxFactory的静态方法)
  • Class的newInstance():放射的方式,只能够调用空参的构造器,权限必须是public
  • Constructor的newInstance():反射的方式,可以调用空参、带参的构造器,权限没有要求
  • 使用Clone():不调用任何构造器,当前类需要实现Cloneable接口,实现clone()方法
  • 使用反序列化:从文件中、或从网络中获取一个对象的二进制流
  • 第三方库Objenesis

【对象创建的六个步骤】

  1. 加载类元信息:判断对象对应的类是否加载、链接、初始化

  2. 为对象分配内存

  3. 处理 并发安全问题

  4. 属性的默认初始化(零值初始化)

  5. 设置对象的对象头

  6. 属性的显式初始化、代码块中初始化、构造器中初始化

JVM执行引擎及基于JVM的对象的实例化过程

JVM执行引擎及基于JVM的对象的实例化过程

【对象的内存布局】

JVM执行引擎及基于JVM的对象的实例化过程

【对象的访问定位】

对象的访问方式主要有两种:句柄访问、直接指针

句柄访问:JVM执行引擎及基于JVM的对象的实例化过程 好处:reference中存储稳定句柄地址,对象被移动(垃圾收集时移动对象很普遍)时只会改变句柄中实例数据指针即可,reference本身不需要被修改。

直接指针:JVM执行引擎及基于JVM的对象的实例化过程

三、StringTable

String字符串,使用一对””引起来表示。实现了Serializable接口,表示字符串是支持序列化的;也实现了Comparable接口,表示String可以比较大小。String声明为final,不可以被继承。在jdk8以前,其内部定义了final char[] value用于存储字符串数据,jdk9时改为bute[]。

定义String对象的两种方式:

String s1 = "hello";// 字面量的定义方式
String s2 = new String("world");

JVM执行引擎及基于JVM的对象的实例化过程

JVM执行引擎及基于JVM的对象的实例化过程

【String的内存分配】

JVM执行引擎及基于JVM的对象的实例化过程

 从jdk6及以前 —–> jdk7 ——> jdk8及以后 字符常量池位置的变化可详见博文:

中方法区的演进模块。

【字符串拼接操作】

JVM执行引擎及基于JVM的对象的实例化过程

字符串拼接面试常见问题:

public class StringTableTest01{

    public static void main(String[] args) {

        String s1 = "javaEE";
        String s2 = "hadoop";

        String s3 = "javaEEhadoop";
        // 两个字面量的字符串+,在编译器就会优化成"javaEEhadoop"
        String s4 = "javaEE" + "hadoop";
        // 如果拼接符号的前后出现了变量,则相当于在堆空间中new String(),具体的内容为拼接的结果"javaEEhadoop"
        String s5 = s1 + "hadoop";
        String s6 = "javaEE" + s2;
        String s7 = s1 + s2;

        System.out.println(s3 == s4);// true
        System.out.println(s3 == s5);// false
        System.out.println(s3 == s6);// false
        System.out.println(s3 == s7);// false
        System.out.println(s5 == s6);// false
        System.out.println(s5 == s7);// false
        System.out.println(s6 == s7);// false

        // intern():判断字符串常量池中是否存在javaEEhadoop值,如果存在,则返回常量池中javaEEhadoop的地址
        // 如果字符串常量池中不存在javaEEhadoop值,则在常量池中加载一份javaEEhadoop,并返回该对象的地址
        String s8 = s6.intern();
        System.out.println(s3 == s8);// true

    }

}

变量字符串相加的底层原理:是创建了一个StringBuilder对象(jdk5.0之后,之前用的是StringBuffer),并通过调用其 append() 方法将两个字符串添加进字符串缓冲区,最后调用 toString() 方法(类似于new String()),转换为字符串

如果字符串拼接符号两边都是字符互传常量或常量引用(final修饰),则仍然使用编译期优化,即非StringBuilder的方式。 针对于final修饰类、方法、基本数据类型、引用数据类型的量的结构时,能使用上final的时候建议使用上(例如:使用final修饰字符串变量时,会将其当作字符串常量,在进行字符串拼接时,就不必再重新new一个对象存放在堆上了,直接再字符串常量池中判断有无)。

public class StringTableTest02 {

    public static void main(String[] args) {

        String s1 = "javaEEhadoop";
        String s2 = "javaEE";
        String s3 = s2 + "hadoop";
        System.out.println(s1 == s3);// false

        final String s4 = "javaEE";// final修饰的s4是字符串常量
        String s5 = s4 + "hadoop";
        System.out.println(s1 == s5);// true

    }

}

【intern()的使用】

JVM执行引擎及基于JVM的对象的实例化过程

即保证变量s指向的是字符串常量池中的数据的两种方式:

  • 方式一:
    • String s = “abcd”;
  • 方式二:
    • String s = new String(“abcd”).intern()
    • String s = new StringBuilder(“abcd”).toString().intern();

下面来一道看似简单,但你大概率做不对的 面试题

public class StringTableTest03 {

    public static void main(String[] args) {

        String s1 = new String("1");
        s1.intern();
        String s2 = "1";
        System.out.println(s1 == s2);

        String s3 = new String("1") + new String("1");
        s3.intern();
        String s4 = "11";
        System.out.println(s3 == s4);

    }

}

问两个输出的结果是多少?

在解答上述问题前,再抛出一个问题: new String(“ab”);会创建几个对象?   new String(“a”) + new String(“b”);呢?

new String(“ab”);创建了2个对象:

  1. 首先,new关键字会在堆空间开辟一个空间,存放String类型的对象
  2. 其次,会在字符串常量池中会存放一个”ab”的对象。

new String(“a”) + new String(“b”);创建了6个对象:

  1. 拼接变量字符串时需要new StringBuilder()对象
  2. 在堆中new String(“a”)对象
  3. 常量池中的”a”对象
  4. 在堆中new String(“b”)对象
  5. 常量池中的”b”对象
  6. StringBuilder的toString()方法会new String(“ab”)对象

强调:在最后一步toString()方法的调用,不会在字符常量池中在生成”ab”对象

在弄明白这两件事后,我们就很容易地能够弄清楚第一个问题:

答案就是:

        在jdk6及以前:两个输出都为false

        在jdk7及以后:第一个输出false,第二个输出true

下面我们逐行解释一下代码:

public class StringTableTest03 {

    public static void main(String[] args) {

        // 注意:这里的堆中"1"对象和字符串常量池中的"1"对象不是同一个对象

        String s1 = new String("1");// s1指向堆中的"1"对象,并在字符串常量池生成"1"对象
        s1.intern();// 调用此方法前,字符串常量池中已经存在了"1"对象,所以这里不必做任何事
        String s2 = "1";// s2指向字符串常量池中的"1"对象
        System.out.println(s1 == s2);// jdk6:false      jdk7/8:false

        // s3变量记录的地址为:new String("11"),s3指向堆中的"11"对象
        // 并且在执行完下一句代码后,常量池中不存在"11"对象
        String s3 = new String("1") + new String("1");
        // 这里intern()在 jdk6及以前 和 jdk7及以后 的作用不同:
        //      jdk6:创建一个新的字符串常量池对象"11",也就是有新的地址
        //      jdk7:此时常量池中并没有创建新的对象"11",而是指向堆空间中的对象"11"
        s3.intern();// 在字符串常量池中生成"11"对象
        String s4 = "11";// s4指向字符串常量池中的"11"对象
        System.out.println(s3 == s4);// jdk6:false      jdk7/8:true

    }

}

下面是在 jdk6 和 jdk7 环境下的图解:

JVM执行引擎及基于JVM的对象的实例化过程JVM执行引擎及基于JVM的对象的实例化过程

 

JVM执行引擎及基于JVM的对象的实例化过程

对于程序中大量存在的字符串,尤其其中存在很多重复字符串时,使用intern()方法可以节省很多内存空间。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/2152.html

(0)
小半的头像小半
0 0

相关推荐

  • FLIP,一种高端优雅但简单易用的前端动画思维 React

    FLIP,一种高端优雅但简单易用的前端动画思维

    0 0112
    小半的头像 小半
    2024年3月16日
  • 使用 fcntl 模块对文件进行加解锁 微信精选

    使用 fcntl 模块对文件进行加解锁

    0 0140
    小半的头像 小半
    2023年2月15日
  • IDEA懒人必备插件:自动生成单元测试,太爽了! Java知音

    IDEA懒人必备插件:自动生成单元测试,太爽了!

    0 0319
    小半的头像 小半
    2022年12月12日
  • 58.Java单例模式面试怎么面? 技术漫谈

    58.Java单例模式面试怎么面?

    0 068
    java小白的头像 java小白
    2024年3月23日
  • Python请求库大合集 Python

    Python请求库大合集

    0 057
    python学霸的头像 python学霸
    2024年4月14日
  • Mybatis-plus_CURD接口-IService 架构设计

    Mybatis-plus_CURD接口-IService

    0 0200
    小半的头像 小半
    2022年10月30日
  • 【260期】Java线程池,这篇能让你和面试官聊了半小时 面试题

    【260期】Java线程池,这篇能让你和面试官聊了半小时

    0 0133
    小半的头像 小半
    2022年5月17日
  • vue 2.x 升级vue3.x 需要注意什么 前端开发

    vue 2.x 升级vue3.x 需要注意什么

    0 058
    李, 若俞的头像 李, 若俞
    2024年4月2日
  • 微服务是何方神圣 后端开发

    微服务是何方神圣

    0 073
    小半的头像 小半
    2022年7月11日
  • Controller 就该这么写,简洁又优雅! Java知音

    Controller 就该这么写,简洁又优雅!

    0 099
    小半的头像 小半
    2022年12月5日
  • React 并发模式到底是个啥? React

    React 并发模式到底是个啥?

    0 072
    葫芦侠五楼的头像 葫芦侠五楼
    2024年3月16日
  • Java JUC LockSupport概述 后端开发

    Java JUC LockSupport概述

    0 086
    小半的头像 小半
    2022年6月16日

站长精选

  • SpringBoot 整合 Redis 全面教程:从配置到使用

    SpringBoot 整合 Redis 全面教程:从配置到使用

    2024年2月16日

  • 小伙在公司用了个 insert into select 居然被开除了?!

    小伙在公司用了个 insert into select 居然被开除了?!

    2023年11月15日

  • Git命令只会抄却不理解?看完原理才能事半功倍!

    Git命令只会抄却不理解?看完原理才能事半功倍!

    2023年10月15日

  • Dubbo-SPI机制

    Dubbo-SPI机制

    2022年11月21日

  • Github 热度飙升,一键生成最近抖音超火的 AI 人物绘图

    Github 热度飙升,一键生成最近抖音超火的 AI 人物绘图

    2022年12月28日

  • Jenkins + Docker 一键自动化部署 SpringBoot 应用最精简流程

    Jenkins + Docker 一键自动化部署 SpringBoot 应用最精简流程

    2023年10月30日

  • 废物利用,拿自己的旧电脑搭建个服务器吧!

    废物利用,拿自己的旧电脑搭建个服务器吧!

    2023年5月5日

  • 腾讯开源的一站式微服务解决方案:SpringCloud Tencent 实践

    腾讯开源的一站式微服务解决方案:SpringCloud Tencent 实践

    2022年11月8日

  • Java 中的 Stream 可以替代 for 循环吗?

    Java 中的 Stream 可以替代 for 循环吗?

    2023年10月30日

  • 看了我的 Mapstruct 用法,同事们也开始悄悄模仿了!

    看了我的 Mapstruct 用法,同事们也开始悄悄模仿了!

    2023年11月24日

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!

深圳SEO优化公司北海seo网站推广桐城网站建设汉中seo排名推荐商丘网站推广工具多少钱宿迁网站制作报价湛江建站公司朔州网站建设设计罗湖网站优化软件公司朔州优秀网站设计广元网站改版推荐天门百度爱采购大芬高端网站设计推荐扬州百度网站优化排名公司丹竹头网站开发商丘网站建设公司鞍山设计网站松原建站哪家好和县seo网站推广报价濮阳网站推广推荐荆门至尊标王推荐日照seo网站优化推荐曲靖百度竞价包年推广价格广元网站改版推荐海南如何制作网站公司宜宾企业网站制作公司揭阳网站推广方案公司哈尔滨百度标王哪家好成都网站建设设计公司果洛企业网站建设哈尔滨网站制作设计价格歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化