烧点脑子使劲看--对象详细讲解

简介: 当Java虚拟机遇到一条new字节码指令时,首先会检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用所代表的类是否已经被加载,如果没有,就必须先将就该类加载到内存中,具体过程见:

一、对象的创建


当Java虚拟机遇到一条new字节码指令时,首先会检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用所代表的类是否已经被加载,如果没有,就必须先将就该类加载到内存中,具体过程见:类的加载过程


在类加载检查通过后,虚拟机就会为这个对象分配内存,内存分配的方式主要有两种:

  • 指针碰撞:如果JVM堆内存是绝对规整的,所有已经使用的内存都放在一边,空闲的内存都放在另一边,中间用一个指针指向分界点,那么只需要将指针往后移动新对象的大小同等距离即可。
  • 空闲列表:如果堆内存不是规整的,那么就无法使用“指针碰撞”的方式来为新对象分配内存,虚拟机就需要维护一张列表,用于记录堆内存上哪一块空间是空闲的,在这个列表中选取一块足够大的内存空间为新对象分配内存,并更新列表。

具体使用哪种内存分配方式是由使用的垃圾收集器是否具有空间压缩整理的能力决定的,使用SerialParNew这种带压缩整理过程的垃圾收集器时,采用的分配算法是指针碰撞。而如果使用CMS这类基于标记-清除算法的垃圾收集器时,将采用空闲列表来分配内存

由于对象的创建在虚拟机中是非常频繁的行为,在并发情况下并不是线程安全的,可能出现为A对象分配内存空间,指针还没来得及修改,对象B又使用了同一块内存空间。解决这个问题又两种可选方案:

  • 采用同步的方式分配内存空间,在Java虚拟机中采用CAS加上失败重试的方式来保证更新操作的原子性。
  • 另一种方案是将内存分配动作按照线程划分在不同的空间中进行,即每个线程再Java堆中预先分配一块小内存,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)。哪个线程需要分配内存,就在哪个线程的本地线程分配缓冲区中分配,只用当本地线程分配缓冲中的空间不够为新对象分配空间了,才需要采用同步的方式分配空间。虚拟机是否使用本地线程分配缓冲,可以通过-XX:+/-UseTLAB参数来设置。

在内存分配完成后,虚拟机还需要对象的对象头进行必要的设置,例如GC分代年龄、这个对象属于哪个类的实例、如何才能找到类的元数据信息、对象的哈希码(实际上对象的哈希码会延后到调用hashCode()方法才计算)等。

执行完上面的操作后,虚拟机还需要执行Class文件中的方法,也就是我们在代码中写的构造函数。


二、对象的内存布局


在HotSpot虚拟机中,对象在堆内存中的存储结构可以分为三个部分:

  • 对象头(Head)

对象头包括两类信息。第一类是用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁;偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机中分别为32个比特和64个比特,称为“Mark Word”。

网络异常,图片无法展示
|

对象头的另一部分是类型指针(Klass Word),即对象指向它的类型元数据的指针,Java虚拟机通过这个指针来确定该对象是属于哪个类的实例,如果对象是一个Java数组,那么对象头中还必须有一块用于记录数组长度。

  • 实例数据(Instance Data)

实例数据是对象真正储存的有效信息,是我们在代码中定义的各种类型的字段内容,包括从父类继承下来的。这部分的存储顺序会受到虚拟机分配策略参数(-XX:FieldsAllocationStyle)和字段在源码中定义的顺序的影响。HotSpot虚拟机默认的分配顺序是:longs/doublesintsshorts/charsbytes/booleansoops(Ordinary Object Pointers, OOPs),父类定义的字段会出现子类前面。

  • 对齐填充(Padding)

对齐填充不是必须的部分,也没有什么特别的含义,仅仅是为了将对象的大小凑到8字节的倍数。

目录
相关文章
|
1月前
|
存储 缓存 安全
面试官:小伙子,能聊明白JMM给你SSP!我:嘚吧嘚吧一万字,直接征服面试官!
面试官:小伙子,能聊明白JMM给你SSP!我:嘚吧嘚吧一万字,直接征服面试官!
31 1
|
9月前
|
设计模式 网络协议 算法
|
9月前
|
设计模式 缓存 算法
花了30天才肝出来,史上最全面Java设计模式总结,看完再也不会忘
Design Patterns: Elements of Reusable Object-Oriented Software(以下简称《设计模式》),一书由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides合著(Addison-Wesley,1995)。这四位作者常被称为“四人组(Gang of Four)”,而这本书也就被称为“四人组(或 GoF)”书。他们首次给我们总结出一套软件开发可以反复使用的经验,帮助我们提高代码的可重用性、系统的可维护性等,解决软件开发中的复杂问题。
122 0
|
算法 架构师 Java
03程序员吃的是青春饭?本质上取决于|学习笔记
快速学习03程序员吃的是青春饭?本质上取决于
85 0
|
存储 Web App开发 程序员
程序猿的血泪史:一定要有数据备份的思想,不然死都不知道咋死的!!!
程序猿的血泪史:一定要有数据备份的思想,不然死都不知道咋死的!!!
170 0
|
算法 Java
|
存储 人工智能 Java
肝了一整天,关于Java数组,你想知道的都在这里!
肝了一整天,关于Java数组,你想知道的都在这里!
156 0
肝了一整天,关于Java数组,你想知道的都在这里!
|
存储 编译器
懂了嘎嘎乱杀,但我赌你会懵——指针进阶终极版
正片开始👀 细化指针这一部分内容,现在着重把一些指针的运用情景搬出来康康,如果对指针盘的非常熟练了,或者指针还出于入门阶段的铁子请绕道(晕头警告) 直接给大家盘个套餐: 一维数组👏
懂了嘎嘎乱杀,但我赌你会懵——指针进阶终极版
|
存储 安全 Java
烧点脑子使劲看--类的加载过程
. 概述 当程序需要使用到某个类时,如果该类还没有被加载到内存中,就需要先将类加载到内存中。类的加载过程分为五个阶段:加载、验证、准备、解析、初始化。
107 0
|
存储 程序员 C语言
指针不过如此,看完后我差点飘了(一)
指针不过如此,看完后我差点飘了
143 0
指针不过如此,看完后我差点飘了(一)

热门文章

最新文章