• cookie。 置顶
    2018-05-19
    对象由三部分组成,对象头,对象实例,对齐填充。
    其中对象头一般是十六个字节,包括两部分,第一部分有哈希码,锁状态标志,线程持有的锁,偏向线程id,gc分代年龄等。第二部分是类型指针,也就是对象指向它的类元数据指针,可以理解,对象指向它的类。
    对象实例就是对象存储的真正有效信息,也是程序中定义各种类型的字段包括父类继承的和子类定义的,这部分的存储顺序会被虚拟机和代码中定义的顺序影响(这里问一下,这个被虚拟机影响是不是就是重排序??如果是的话,我知道的volatile定义的变量不会被重排序应该就是这里不会受虚拟机影响吧??)。
    第三部分对齐填充只是一个类似占位符的作用,因为内存的使用都会被填充为八字节的倍数。

    还是个初学者。以上是我了解,不知道有没有错,希望老师能告知。
    展开
     2
     116
  • Kyle 置顶
    2018-05-19
    节选自《深入理解JAVA虚拟机》:
    在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

    HotSpot虚拟机的对象头包括两部分信息,第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit,官方称它为"Mark Word"。

    对象头的另外一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。并不是所有的虚拟机实现都必须在对象数据上保留类型指针,换句话说,查找对象的元数据信息并不一定要经过对象本身,这点将在2.3.3节讨论。另外,如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中却无法确定数组的大小。

    接下来的实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。

    第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。
    展开
    
     69
  • kursk.ye
    2018-06-13
    这篇文章写得比较零散,整体思路没有串起来,其实我觉得可以从这么一条线索理解这个问题。原始数据类型和 Java 泛型并不能配合使用,也就是Primitive Types 和Generic 不能混用,于是JAVA就设计了这个auto-boxing/unboxing机制,实际上就是primitive value 与 object之间的隐式转换机制,否则要是没有这个机制,开发者就必须每次手动显示转换,那多麻烦是不是?但是primitive value 与 object各自有各自的优势,primitive value在内存中存的是值,所以找到primitive value的内存位置,就可以获得值;不像object存的是reference,找到object的内存位置,还要根据reference找下一个内存空间,要产生更多的IO,所以计算性能比primitive value差,但是object具备generic的能力,更抽象,解决业务问题编程效率高。于是JAVA设计者的初衷估计是这样的:如果开发者要做计算,就应该使用primitive value如果开发者要处理业务问题,就应该使用object,采用Generic机制;反正JAVA有auto-boxing/unboxing机制,对开发者来讲也不需要注意什么。然后为了弥补object计算能力的不足,还设计了static valueOf()方法提供缓存机制,算是一个弥补。
    展开
     7
     221
  • 公号-云原生程序员
    2018-05-19
    1 int和Integer

    JDK1.5引入了自动装箱与自动拆箱功能,Java可根据上下文,实现int/Integer,double/Double,boolean/Boolean等基本类型与相应对象之间的自动转换,为开发过程带来极大便利。

    最常用的是通过new方法构建Integer对象。但是,基于大部分数据操作都是集中在有限的、较小的数值范围,在JDK1.5 中新增了静态工厂方法 valueOf,其背后实现是将int值为-128 到 127 之间的Integer对象进行缓存,在调用时候直接从缓存中获取,进而提升构建对象的性能,也就是说使用该方法后,如果两个对象的int值相同且落在缓存值范围内,那么这个两个对象就是同一个对象;当值较小且频繁使用时,推荐优先使用整型池方法(时间与空间性能俱佳)。

    2 注意事项

    [1] 基本类型均具有取值范围,在大数*大数的时候,有可能会出现越界的情况。
    [2] 基本类型转换时,使用声明的方式。例:long result= 1234567890 * 24 * 365;结果值一定不会是你所期望的那个值,因为1234567890 * 24已经超过了int的范围,如果修改为:long result= 1234567890L * 24 * 365;就正常了。
    [3] 慎用基本类型处理货币存储。如采用double常会带来差距,常采用BigDecimal、整型(如果要精确表示分,可将值扩大100倍转化为整型)解决该问题。
    [4] 优先使用基本类型。原则上,建议避免无意中的装箱、拆箱行为,尤其是在性能敏感的场合,
    [5]     如果有线程安全的计算需要,建议考虑使用类型AtomicInteger、AtomicLong 这样的线程安全类。部分比较宽的基本数据类型,比如 float、double,甚至不能保证更新操作的原子性,可能出现程序读取到只更新了一半数据位的数值。
    展开
    
     115
  • 行者
    2018-05-20
    1. Mark Word:标记位 4字节,类似轻量级锁标记位,偏向锁标记位等。
    2. Class对象指针:4字节,指向对象对应class对象的内存地址。
    3. 对象实际数据:对象所有成员变量。
    4. 对齐:对齐填充字节,按照8个字节填充。

    Integer占用内存大小,4+4+4+4=16字节。
    展开

    作者回复: 不错,如果是64位不用压缩指针,对象头会变大,还可能有对齐开销

    
     25
  • Gerald
    2018-05-29
    为什么我感觉都这么难啊😭

    作者回复: 感谢反馈,具体哪个方面,我可以调整一下,尽量照顾不同基础的朋友

     1
     15
  • George
    2018-05-25
    计算对象大小可通过dump内存之后用memory analyze分析

    作者回复: 嗯,也可以利用:
    jol,jmap,或者instrument api(Java agent)等等

    
     11
  • 巴西
    2018-12-02
    其实除了存储空间的区别外,基本数据类型是有默认值的,而对象数据类型没有默认值。比如从数据库中查询用户年龄,如果用户并没有设置年龄信息,数据库中代表年龄的列age =null ,那么在使用基本数据类型接收年龄值的时候就无法区分用户是年龄为0还是未设置年龄的情况。

    所以决定使用int还是integer的时候除了考虑性能因素,还要考虑业务场景。
     2
     10
  • George
    2018-05-25
    java内存结构
    对象头:
    markword:用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁等。这部分数据长度在32位机器和64位机器虚拟机中分别为4字节和8字节;
    lass指针:即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象属于哪个类的实例;
    length:如果是java数组,对象头必须有一块用于记录数组长度的数据,用4个字节来int来记录数组长度;
    实例数据
    实例数据是对象真正存储的有效信息,也是程序代码中定义的各种类型的字段内容。无论是从父类继承下来还是在子类中定义的数据,都需要记录下来
    堆积填充
    对于hotspot迅疾的自动内存管理系统要求对象的起始地址必须为8字节的整数倍,这就要求当部位8字节的整数倍时,就需要填充数据对其填充。原因是访问未对齐的内存,处理器需要做两次内存访问,而对齐的内存访问仅需一次访问
    展开
    
     8
  • Miaozhe
    2018-05-21
    杨老师,问个问题,如果使用原始类型int定义一个变量在-128和127之间,如int c = 64;会放入Integer 常量缓存吗(IntegerCache)?编译器是怎么操作的?

    作者回复: 不需要,不是对象

    
     4
  • jutsu
    2018-05-20
    老师的讲解让我想起了科比主导的 细节栏目
    
     4
  • 云泥
    2019-01-27
    缓存的原理是怎样的?感觉这部分还没理解

    作者回复: 建议你跟踪下类似Integer.valueOf(xxx),看看IntegerCache的实现,底层是个常量数组,在静态初始化块中创建并缓存对象

     1
     3
  • 麦田
    2018-05-19
    周末了是不是没人看文章了
    
     3
  • 文
    2019-08-25
    老师能不能把jvm底层和基本使用拆开,一会儿说基本使用的时候太快东西讲得很少,突然间就转jvm里面,让对于jvm方面比较基础弱的同学看着会很痛苦,拆开便于理解和分情况浏览学习
    
     2
  • 倚楼听风雨
    2019-04-28
    valueOf和parseInt有什么区别?
     2
     2
  • 步*亮
    2018-05-19
    缓存用得很巧秒,值得借鉴
    
     2
  • Slug
    2018-05-19
    感谢老师放假还在写文章,学到很多,钱花的很值。
    
     2
  • Strom
    2018-05-19
    原始数据类型貌似反射也不行。
    
     2
  • 橙子大魔王
    2019-03-03
    特别的是,部分比较宽的数据类型,比如 float、double,甚至不能保证更新操作的原子性,可能出现程序读取到只更新一半的问题。

    为什么是float。我觉得是long和double= =
    
     1
  • 云飞
    2018-10-15
    想知道Integer 不就是4字节嘛?为什么要从对象角度考虑就变成了4+4+4+4=16字节?

    作者回复: header 补齐,如果仅仅是表示数据,object是个高成本的东西,而且开销不仅是空间,引用结构也会影响内存布局

    
     1
我们在线,来聊聊吧