基于 HotSpot
根本类型对象的创立
1 当虚拟机遇到一条 new 指令时,尝试在常量池中定位到相干类的符号援用
2 查看这个符号援用代表的类是否曾经加载,解析,初始化,如果没有先执行类加载
3 实现 2 后可确定对象所需的内存大小
4 从堆中划分出相应大小的内存。
5 初始化对象:对象的哈希码,gc 分代年龄,对应类的信息。
6 依据代码设置对象初始值。
问题一:
步骤 3 是如何确定对象所需内存的大小的?
首先看一下对象在内存中的存储布局:
hotspot 规定对象的起始地址必须是 8 字节的整倍数,即对象的大小必须是 8 字节的整数倍。对象头个别格局较固定,能够保障这一点,当实例数据不满足的时候,须要对齐填充局部来一起保障。
问题二:
步骤 4 中是如何从堆中划分内存的?
堆中划分内存有两种办法:指针 和 闲暇列表。应用哪种形式取决于堆是否是规整的(堆是否能规整取决于应用的垃圾回收算法)。
规整的意思是说堆中应用过的内存和闲暇内存有显著的划分界线,而不是混在一起的。
如果是规整的,那么就能够应用指针法,在应用过的内存和闲暇内存的分界点用一个指针示意,分配内存时只有将指针向闲暇内存方向挪动一段与对象内存大小相等的间隔。
如果不是规整的,那只能应用闲暇列表,闲暇列表是指虚拟机保护一个列表,记录哪些内存块是应用过的哪些是闲暇的,分配内存时从列表中抉择一块满足对象大小的内存块。这里如何抉择内存块,预计就是学生时代学的操作系统讲的那些内容了,如何保障内存碎片较少之类的(后续整顿)
hotspot 应用的应该是指针
分配内存的时候还波及到并发的问题,两种解决形式:
1 对分配内存这种操作进行同步解决,CAS 保障操作的原子性
2 本地线程调配缓冲 TLAB,事后为每个线程调配一小块内存 TLAB,须要内存时各线程先在本人的 TLAB 上调配,当 TLAB 不够用的时候才会须要同步。
CAS:
简略形容下,大体采纳的是乐观锁的思维,不应用锁,多个线程去改同一个变量时,都能够尝试去改,只会有一个线程胜利,失败的线程也会立即失去反馈,不会阻塞。
CAS 中有三个变量,内存中的值 V,预期原值 A,新值 B,每个线程尝试去扭转量的时候,先判断 A 和 V 是否相等,如果雷同,则将 B 更新到内存,否则更新失败。