面向对象
众所周知, 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).
结语
到这里, 对于虚拟机, 对象就已经找到了自己的座位并落座, 下一篇, 我们来介绍一下对象中都有什么.
公众号
来源: https://www.cnblogs.com/viyoung/p/11456892.html