学习笔记5——对象、直接内存、执行引擎,string

学习笔记系列开头惯例发布一些寻亲消息

链接:https://baobeihuijia.com/bbhj/contents/3/192486.html

创建对象的步骤

  • 对象对应的类是否被加载,链接(链接到真实的内存地址),初始化(类初始化)

  • 计算对象占用大小,在堆中划分内存

    • 内存规整:指针碰撞法(指针作为分界线向后移动)
    • 内存不规整:空闲列表分配(记录哪些内存是可用的)
    • 取决于java堆采用什么垃圾回收机制内存是否规整
  • 处理并发安全问题

    • 区域加锁
    • 线程预留TLAB
  • 初始化分配的空间:所有属性赋默认初始化值

  • 设置对象头

  • 对象初始化<显式初始化、代码块中初始化、构造器初始化>

对象在堆中的布局

  • 对象头

    • 运行时元数据

      • 在堆中的首地址(哈希值)
      • GC分代年龄
      • 锁状态
    • 类型指针:指向元空间的类型

  • 实例数据:各种类型的字段【先放父类的变量、相同宽度的分配在一起】

  • 对齐填充

对象访问定位

  • 句柄访问

    • 浪费空间
    • 访问效率较低
    • 优点:栈空间引用地址比较稳定,就算对象发生了变化,也只需要修改句柄指针,栈中的引用无需变化
  • 直接指针

直接内存(元数据)

  • 读写文件,需要与磁盘交互,需要由用户态切换到内核态
    • 一般的需要经过两层
  • 除了第一种,对于一些读写比较频繁的场合,java虚拟机提供了NIO库,使得用户程序可以操作一块由操作系统划出的直接内存,不受JVM的限制和管理,元数据就是这样实现的

执行引擎

  • 需要了解编译和汇编过程

    • 机器指令码:cpu直接识别执行,不同cpu对同一机器指令码的识别不同,可能对A是相加,对B就是赋值

    • 指令:指令就是将一些常用的机器指令码用符号的形式记录,比如一串二进制可以表示为add

    • 指令集:由于cpu之间对于机器指令识别的差异,所以对于不同种类cpu,都要有对应的(指令,二进制码)表,当然这是提前定义在cpu内部的

    • 汇编语言:助记符代替操作码,地址符号代替操作数的地址

    • 高级语言:高级语言一张嘴,机器指令跑断腿

  • 执行引擎的任务就是将字节码指令解释为平台上的本地机器指令,JVM执行引擎提供了三种方式

    • AOT编译器:是一种由源代码直接到机器码的方法,但是对于java 的动态特性并不友好,所以是一种牺牲质量换取性能的策略,如动态类加载无法实现
    • 解释器(字节码->机器码)
      • 将字节码翻译为机器码,可以很快启动
    • JIT编译器(java的即时编译技术just in time,相比于AOT,JIT是在程序运行过程中进行转换)(分为两类)
      • 寻找热点代码,对于这些频繁被调用的热点代码进行深度优化,然后将字节码编译为机器码后再启动,编译需要花费点时间,如果优化失败则还是采用翻译器
      • 热点代码探测:这里的热点代码指的是一段时间内被调用频率很高的代码,而不是从执行开始单纯的次数最多的代码(有衰减机制)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • JIT编译器:将字节码转化为本地机器码(启动慢过程很快)

    • c1编译模式:进行简单、可靠的优化耗时短,编译快,如有必要将加入性能监控的逻辑
    • c2编译模式:会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。
  • 为什么java需要编译器和翻译器合并?

String Table

  • 为什么要移动到堆中:想跟随堆中的其他对象一起进行垃圾回收,避免字符串常量越来越多导致内存溢出(原来常量池位于永久代,永久代只有full gc才会清理比较慢,移出来是为了让字符串常量池得到更加频繁的清理)
  • 拼接
    • 常量拼接直接字节码编译优化生成结果,存在常量池("javaee"),常量池中没有重复的元素,可以通过不同的变量名来索引相同的地址
    • 只要带一个变量,则拼接原理为stringbuilder对象append,结果放入堆中 / 如果是final string拼接那么还是按照常量拼接来
      • 如果没有显式操作,还是使用+,那么就是每次+都会创建builder对象和string对象,以stringbuilder的方式拼接
      • 显式调用stringbuilder.append后,只会调用一个builder的append,而且不会和常量池发生关系
    • 拼接结果调用intern方法,如果该字符串不存在就会将当前字符串放入常量池,返回结果的指向必须为常量池中的字符串实例,该方法确保字符串在内存中只有一份拷贝(intern就是让当前对象的值在池中也存一份,如果已经有了那就算了,还是指着对象,没有的话就存一份指向池中)
  • 池中的string pool是一个固定大小的hashtable,不会存储相同内容的字符串的
  • 显式的+两个双引号,或者tostring之后就会存储到常量池中,如果是对象或者存在一个变量的的话,采用的是stringbuilder进行的,所以不会存到常量池
  • StringBuffer的toString方法会调用new String, 在堆中新建对象

String的intern()方法在不同JDK版本的区别-CSDN博客

java 面试题: new String() 会创建几个对象?_new string("a") + new string("b") 会创建几个对象?-CSDN博客

相关推荐
胡西风_foxww19 分钟前
【ES6复习笔记】数值扩展(16)
前端·笔记·es6·扩展·数值
Somnus陳1 小时前
软考架构师笔记-计算机系统组成-1
笔记·系统架构
LuH11242 小时前
【论文阅读笔记】IC-Light
论文阅读·笔记
汤姆和佩琦2 小时前
2024-12-25-sklearn学习(20)无监督学习-双聚类 料峭春风吹酒醒,微冷,山头斜照却相迎。
学习·聚类·sklearn
是小菜呀!3 小时前
实验四 触发器
笔记
悲伤小伞3 小时前
C++_数据结构_详解二叉搜索树
c语言·数据结构·c++·笔记·算法
好学近乎知o3 小时前
正则表达式(学习Django过程中可能涉及的)
学习·正则表达式·django
雨中奔跑的小孩3 小时前
爬虫学习案例8
爬虫·学习
jieshenai3 小时前
使用 VSCode 学习与实践 LaTeX:从插件安装到排版技巧
ide·vscode·学习
灰太狼不爱写代码6 小时前
CUDA11.4版本的Pytorch下载
人工智能·pytorch·笔记·python·学习