java堆上的对象

Java堆上的对象

1.对象的创建(new Object)

  • 创建过程:先检查能否在常量池中定位到一个类的符号引用,并且检查其代表的类是否被加载、解析和初始化过;若无,执行类加载过程;然后为新生对象分配内存(类加载完成后即可确定对象大小);内存分配完后,内存空间初始化为零;接下来,对对象的类信息、类的元数据信息、对象哈希码、GC分代年龄进行设置(这些信息存放在对象头中(Object Header));然后执行<init>方法(按照程序员的意愿进行初始化)
  • java堆上内存分配的两种方式:”指针碰撞“(中间一个指针作为空闲内存和用过内存的分界点)、”空闲列表“(列表记录哪些内存块可用),采用哪种方式取决于垃圾收集器是否带有压缩整理功能。 分配内存时考虑线程安全问题:CAS失败重试,或者使用本地线程分配缓冲(TLAB)(类似于ThreadLocal)

2.对象的内存布局

  • 3个区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding).
  • 对象头; 两部分信息:第一部分用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有锁、偏向线程ID、偏向时间戳等;另一部分是类型指针,即对象指向类元数据的指针。 如果对象是Java数组,对象头中需要记录数组长度

3.对象的访问定位

通过栈上reference数据来操作,主流的访问方式两种:

  • 句柄:reference存储的是句柄地址,句柄池中的句柄包含了对象实例数据和类型数据的地址信息
  • 直接指针访问:reference中存放的直接就是对象地址。
  • 对比:句柄方式稳定,对象移动时,只需改变句柄中的实例数据指针,reference不用变;直接指针方式速度更快,因为节省了一次指针定位的时间开销。Sun HotSpot使用指针方式。

String.intern()是一个Native方法,作用:若字符串常量池中已经包含了一个等于String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
StirngBuilder创建的字符串实例在Java堆上。

猜你喜欢

转载自blog.csdn.net/l947069962/article/details/84330329