共计 1103 个字符,预计需要花费 3 分钟才能阅读完成。
面向对象
众所周知,Java 是一门面向对象的高级编程语言,那么现在问题来了,对象从哪来呢?有些人会说通过 new 关键字来创建一个对象,说的很好,本篇我们就来解密在 new 一个对象的过程中,JVM 都给我们做了什么工作。
走哪来,到哪去
一个对象的诞生必定有一个类,通常我们都是通过 new 关键字实例化一个类来获取该类的一个对象,类在加载的过程中会经历一系列的检查,解析,初始化等一系列的过程,我们会在后面详细的分步骤进行讲解,这里我们只关心对象。
下面对象就要被加载到我们的虚拟机内存的堆内存中,加载到堆内存中也就意味着这个对象需要一定的空间,那么这个空间走哪来呢?这里 JVM 规范给出了两种情况:
指针碰撞
所谓指针碰撞,前提的条件是 JVM 的堆内存是绝对工整的,中间有一个指针作为分割空闲空间和已用空间的”三八线“,指针碰撞一般发生在 Eden 区,跟踪在 Eden 创建的最后一个对象,这个对象会被放在 Eden 的顶部。如果有足够的空间,对象就会被创建在 Eden,并且被放置在顶部,然后将指针向上移动(如果你玩过俄罗斯方块,你就应该明白,说白了就是一种不可消除绝对规整的俄罗斯方块),当俄罗斯方块被堆满之后,就会触发一次 Minor GC(关于 GC 的知识,我们在后面来讲解)
打个比方来说,一个班里有很多座位,学生必须按照顺序来坐,这样只需要知道最后一个进来的学生坐哪就知道下一个学生坐哪,以及有没有空位~
在单线程的情况下,我们这样使用是没有什么问题的,但是如果处于多线程并发的情况,就会出现分配空间失败的情况,打个比方来说,就是把一个位置同时卖给了两个人,这种情况势必就会打架,这种情况下,我们可以采取两种方法来解决这个问题:
- 使用 CAS+ 失败重试保证更新操作的原子性
CAS(Compare And Swap),关键是 3 个操作数。
内存值 V
旧的预期值 A
要修改的新值 B
当且仅当预期值 A 和内存值 V 相同时,将内存值 V 修改为 B,否则什么都不做。
- 第二种方法,结合我们上节课说到的 TLAB 来实现,在分配内存的时候在每个线程上的 TLAB(Thread Local Allocation Buffer)区域进行分配,这里分配的时候可以初始化为零值,这一步操作保证了对象实例字段在 Java 代码中不赋值就可以直接使用。
Free List
另一种情况是当堆内存不规整的情况下(学生不要排排坐),JVM 会把没来上课的学生(未使用的内存)记到小本本上,当有新学生(新的对象)来上课的时候,可以去看本本上的座位图给学生安排座位~
这个 JVM 的小本本就叫做空闲列表(Free List)。
结语
到这里,对于虚拟机,对象就已经找到了自己的座位并落座,下一篇,我们来介绍一下对象中都有什么。