简单了解对象实例化过程

本文详细解释了Java对象在堆内存中的分配过程,涉及新生代和老年代的划分,以及垃圾回收机制(如指针碰撞、TLAB和CAS)。遇到内存不足时,文章讨论了YoungGC和FullGC的策略以及可能出现的OOM异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开始我们知道对象的创建过程包括以下几步:

  1. 类加载

  2. 实例化

  3. 初始化

  4. 引用赋值

这几步一般来讲是顺序进行的,不过由于硬件层面的一些优化,可能会发生指令重排的情况,导致3、4步调换位置,我们在程序中就会看到NPE空指针异常,通常可以用volatile修饰这个变量来解决,不过我们今天主要谈谈这个实例化过程,也就是给对象分配内存的过程。

在Java程序,我们绝大多数的对象都在堆内分配内存,只有少部分的对象经过JIT的逃逸分析之后会在栈上分配内存,那对于大多数对象来说,具体是在堆内的什么位置分配内存呢,我们需要首先来看看堆内更加详细的图

image-20240302222528855

堆内的对象会被分代存储,一个是新生代(包括Eden、From、To)和一个老年代,他们的内存大小比例默认是新生代:老年代 = 2:1,在新生代内部,Eden:From:To的大小比例默认是8:1:1。

新对象一般会在Eden进行分配,除了一些大对象(数组、字符串)直接进入到老年代,这样可以减少GC后对这些大对象的移动(因为新生代使用的是标记-整理算法),在分配对象内存的时候我们需要考虑Eden还有哪些空闲的区域,这里JVM针对不同的垃圾回收器用了两种办法:

  • 指针碰撞:适合没有内存碎片的垃圾回收器

  • 空闲链表:适合有内存碎片的垃圾回收器,如CMS

同时考虑到分配对象内存的时候会有并发问题,JVM有两种机制来避免并发问题:

  • 一个是TLAB(这个是JVM给线程分配的一块私有的空间,大概是Eden的1%),在TLAB内分配对象是没有并发问题的

  • 另一个是CAS + 失败重试,利用操作系统的原子指令给对象分配内存

那如果发现Eden已经没有足够大小的内存来分配给对象怎么解决?

大致来说就是先考虑Young GC,如果是JVM判断Young GC是有风险的,那么需要用对象担保机制,最后的办法就是Full GC,如果是Full GC后依旧不够内存分配给新对象,JVM会抛出OOM异常

image-20240302224829513

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值