Su的技术博客

  • 首页
  • Java
  • MySQL
  • DDD
  • 事故复盘
  • 架构方案
  • Other
  • 工具
  • 打赏
  • 关于
  1. 首页
  2. Java
  3. 正文
                           

【原创】笔记 | Java对象探秘

2020-03-20 37点热度 0人点赞 0条评论
点击上方蓝色字关注我们~

  

题外话:Java都有对象,那你的对象在哪里呢?那我也来new一个吧。

了解下Java是怎么创建对象,并且在内存布局和访问定位,可以很好的帮助我们认识虚拟机JVM底层的原理。

这里只是针对HotSpot虚拟机Java对象。



1

对象的创建


 ■创建过程
【虚拟机视角】
1、检查这个指令的参数是否能在常量池中定位到一个类的符号引用
2、检查这个符号引用代表的类是否已被加载、 解析和初始化过
3、类未被加载, 那必须先执行相应的类加载过程
4、为新生对象分配内存
5、对象实例字段初始化零值
6、对象必要设置
 ①对象是哪个实例
 ②如何才能找到类的元数据信息、对象哈希码(调用hashCode时计算)、对象的GC分代年龄等信息。

【程序视角】
7、对象创建刚刚开始
 ① 构造函数, 即Class文件中的<init>()方法还没有执行
 ② new指令之后会接着执行<init>()方法, 按照程序员的意愿对对象进行初始化。
  
■并发问题
方案一:对分配内存空间做同步处理——采用CAS重试保证更新操作的原子性
方案二:内存分配的动作按照线程划分在不同的空间之中进行,线程分配缓冲TLAB(Thread Local Allocation Buffer),只有本地缓冲区用完了, 分配新的缓存区时才需要同步锁定。-XX:+/-UseTLAB(开启关闭参数)




2

对象内存布局


■对象头(Header)
用于存储对象自身的运行时数据:
哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。

类型指针:
对象指向它的类型元数据的指针。

■实例数据(Instance Data)
对象真正存储的有效信息
字段存储顺序
① 虚拟机分配策略参数(-XX:FieldsAllocationStyle参数)
② 在Java源码中定义顺序

■对齐填充(Padding)
①不是必然存在,没有特别含义
②占位符作用
③对象起始地址必须是8字节整数倍--任何对象大小都是8字节整数倍




3

对象访问定位


Java会通过栈上的reference数据来操作堆上的具体对象。

■访问方式
句柄
Java堆中将可能会划分出一块内存来作为句柄池, reference中存储的就是对象的句柄地址, 而句柄中包含了对象实例数据与类型数据各自具体的地址信息。

好处
reference中存储的是稳定句柄地址, 在对象被移动(垃圾收集时移动对象是非常普遍的行为) 时只会改变句柄中的实例数据指针, 而reference本身不需要被修改。

直接指针
HotSpot虚拟机。Java堆中对象的内存布局就必须考虑如何放置访问类型数据的相关信息,reference中存储的直接就是对象地址,如果只是访问对象本身的话,就不需要多一次间接访问的开销。

好处
速度更快,它节省了一次指针定位的时间开销,由于对象访问在Java中非常频繁,因此这类开销积少成多也是一项极为可观的执行成本。


题外话:Java的对象创建过程多么繁琐复杂,那你(直男)在追对象的时候也就不能太着急了。:)


■总结:

1、对象的创建:从虚拟机的视角和程序的视角。虚拟机的视角就从字节码开始,一直进行相关的初始化过程,程序的视角才是真正执行构造器时<init>()进行字段的初始化。

并且会存在并发问题,有两种方案可以解决:一是使用CAS并发同步,另一种是使用线程分配缓存区TLAB(类似隔离)。

2、对象的内存布局:对象头、实例数据、对齐填充。
  • 对象头:包含了对象运行时的一些数据,比如:哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。


  • 实例数据:对象真正存储的有效信息,将对象字段等数据进行存储,并且字段存储的顺序是根据虚拟机分配策略参数和在源码中定义的顺序来决定的。


  • 对齐填充:不是必然存在,只是为了占位符作用,原因是对象起始地址必须是8字节整数倍--任何对象大小都是8字节整数倍。


3、对象的访问方式:有句柄和直接指针两种方式。HotSpot虚拟机使用的是直接指针方式,原因是速度更快,它节省了一次指针定位的时间开销。


参考资料:
《深入理解Java虚拟机:JVM高级特性与最佳实践》
这是一本经典的书,有兴趣的可以买去看看↓:第三版,2019.12出版


推荐阅读

  • 互联网Code Review最佳实践分享

  • dubbo面试题!会这些,说明你看懂了dubbo源码

  • Kafka面试题!掌握它才说明你真正懂Kafka

  • Netty 5.0为啥被舍弃?原因竟然是...

  • 中台之上——业务架构系列【汇总】

  • 必备瑞士军刀IDEA插件,你使用了哪些

  • 加入:互联网基础/架构交流群


-关注搬运工来架构,与优秀的你一同进步-

本文仅供学习!所有权归属原作者。侵删!文章来源: 搬运工来架构

标签: 原创
最后更新:2020-03-20

Cocodroid

专注Java后端,分享技术。

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

最新 热点 推荐
最新 热点 推荐
殷浩详解DDD 第四讲:领域层设计规范 既生@Resource,何生@Autowired? Go整洁架构实践 接口优化的常见方案实战总结 QQ音乐高可用架构体系 构建一个布隆过滤器 —— Building a Bloom filter
殷浩详解DDD 第四讲:领域层设计规范Redis为什么这么快?构建一个布隆过滤器 —— Building a Bloom filterQQ音乐高可用架构体系接口优化的常见方案实战总结Go整洁架构实践
JAVA字节码增强解密(上) Go整洁架构实践 笔记 | 面试官问我:TCP与UDP的区别 笔记08 | 搜狗面试题:IO多路复用之select、poll、epoll的区别 Eureka源码剖析之三:服务拉取 Arthas实战-线上热更新代码只需3步

@Autowired (1) @Resource (1) API网关 (1) ddd (6) DP (1) ElasticSearch (1) eureka (7) go (1) HTTP (1) IDEA (1) iOS (1) Java (8) JSR (1) QQ音乐 (1) repository (1) Spring (1) SQL优化 (1) 代理 (1) 依赖注入 (1) 同城双活 (1) 垃圾回收 (1) 定时任务 (1) 容灾 (1) 布隆过滤器 (1) 异地双活 (1) 接口优化 (1) 故障转移 (1) 数据库 (2) 整洁架构 (1) 文件网关 (1) 方案 (2) 服务续约 (1) 注册中心 (7) 流水账 (1) 流量 (1) 第五 (1) 线上案例 (1) 线上问题 (2) 缓存 (1) 缓存击穿 (1) 编译 (3) 网络 (3) 聊聊 (1) 订单 (1) 设计规范 (1) 详解 (1) 连接池 (1) 限流 (1) 领域驱动设计 (4) 高可用 (1)

COPYRIGHT © 2014-2023 verysu.com . ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备15033072号-2