JVM三JVM虚拟机

对象的创建流程与内存分配

对象内存分配方式

​ 内存分配的方法有两种:不同垃圾收集器不一样

  • 指针碰撞(Bump the Pointer)
  • 空闲列表(Free List)
分配方法 说明 收集器
指针碰撞(Bump thePointer) 内存地址是连续的(新生代) Serial 和ParNew 收集器
空闲列表(Free List) 内存地址不连续(老年代) CMS 收集器和Mark-Sweep 收集器

指针碰撞示意图

内存分配安全问题

在JVM中有两种解决办法:

  1. CAS 是乐观锁的一种实现方式。虚拟机采用 CAS 配上失败重试的方式保证更新操作的原子性。
  2. TLAB本地线程分配缓冲(Thread Local Allocation Buffer即TLAB):为每一个线程预先分配一块内存

JVM在第一次给线程中的对象分配内存时,首先使用CAS进行TLAB的分配。当对象大于TLAB中的剩余内存或TLAB的内存已用尽时,再采用上述的CAS进行内存分配。

对象内存分配流程

对象怎样才会进入老年代

进入老年代的条件:四种情况

  1. 存活年龄太大,默认超过15次【-XX:MaxTenuringThreshold】
  2. 动态年龄判断:MinorGC之后,发现Survivor区中的一批对象的总大小大于了这块Survivor区的50%,那么就会将此时大于等于这批对象年龄最大值的所有对象,直接进入老年代。
  3. 大对象直接进入老年代:前提是Serial和ParNew收集器
  4. MinorGC后,存活对象太多无法放入Survivor

空间担保机制:当新生代无法分配内存的时候,我们想把新生代的老对象转移到老年代,然后把新对象放入腾空的新生代。此种机制我们称之为内存担保。

  • MinorGC前,判断老年代可用内存是否小于新时代对象全部对象大小,如果小于则继续判断
  • 判断老年代可用内存大小是否小于之前每次MinorGC后进入老年代的对象平均大小
    • 如果是,则会进行一次FullGC,判断是否放得下,放不下OOM
    • 如果否,则会进行一些MinorGC:
      • MinorGC后,剩余存活对象小于Survivor区大小,直接进入Survivor区
      • MinorGC后,剩余存活对象大于Survivor区大小,但是小于老年代可用内存,直接进入
        老年代
      • MinorGC后,剩余存活对象大于Survivor区大小,也大于老年代可用内存,进行FullGC
      • FullGC之后,任然没有足够内存存放MinorGC的剩余对象,就会OOM

对象内存布局

在堆中,对象里面都有些啥?

  1. 对象头(Header):Java对象头占8byte。如果是数组则占12byte。因为JVM里数组size需要使用4byte存储。

    • 标记字段MarkWord:
      • 用于存储对象自身的运行时数据,它是synchronized实现轻量级锁和偏向锁的关键。
      • 默认存储:对象HashCode、GC分代年龄、锁状态等等信息。
      • 为了节省空间,也会随着锁标志位的变化,存储数据发生变化。
    • 类型指针KlassPoint:
      • 是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例
      • 开启指针压缩存储空间4byte,不开启8byte。
      • JDK1.6+默认开启
    • 数组长度:如果对象是数组,则记录数组长度,占4个byte,如果对象不是数组则不存在。
    • 对齐填充:保证数组的大小永远是8byte的整数倍。
  2. 实例数据(Instance Data):生成对象的时候,对象的非静态成员变量也会存入堆空间

  3. 对齐填充(Padding):JVM内对象都采用8byte对齐,不够8byte的会自动补齐。


对象头的大小:

对象头信息是与对象自身定义的数据无关的额外存储成本。考虑到虚拟机的空间效率,Mark Word被设计成一个非固定的数据结构,以便在极小的空间内,尽量多的存储数据,它会根据对象的状态复用自己的存储空间,也就是说,Mark Word会随着程序的运行发生变化,变化状态如下(JDK1.8)。

基本数据类型和包装类的内存占用情况:

如何访问一个对象呢

有两种方式:

  1. 句柄:稳定,对象被移动只要修改句柄中的地址
  2. 直接指针:访问速度快,节省了一次指针定位的开销


相关推荐
学到头秃的suhian2 小时前
JVM-类加载机制
java·jvm
NEFU AB-IN9 小时前
Prompt Gen Desktop 管理和迭代你的 Prompt!
java·jvm·prompt
唐古乌梁海14 小时前
【Java】JVM 内存区域划分
java·开发语言·jvm
众俗15 小时前
JVM整理
jvm
echoyu.15 小时前
java源代码、字节码、jvm、jit、aot的关系
java·开发语言·jvm·八股
代码栈上的思考1 天前
JVM中内存管理的策略
java·jvm
thginWalker1 天前
深入浅出 Java 虚拟机之进阶部分
jvm
沐浴露z1 天前
【JVM】详解 线程与协程
java·jvm
thginWalker1 天前
深入浅出 Java 虚拟机之实战部分
jvm
程序员卷卷狗3 天前
JVM 调优实战:从线上问题复盘到精细化内存治理
java·开发语言·jvm