1

基于HotSpot

基本类型对象的创建

1 当虚拟机遇到一条new指令时,尝试在常量池中定位到相关类的符号引用

2 检查这个符号引用代表的类是否已经加载,解析,初始化,如果没有先执行类加载

3 完成2后可确定对象所需的内存大小

4 从堆中划分出相应大小的内存。

5 初始化对象:对象的哈希码,gc分代年龄,对应类的信息。

6 根据代码设置对象初始值。

问题一:

步骤3是如何确定对象所需内存的大小的?

首先看一下对象在内存中的存储布局:

image.png

hotspot规定对象的起始地址必须是8字节的整倍数,即对象的大小必须是8字节的整数倍。对象头一般格式较固定,可以保证这一点,当实例数据不满足的时候,需要对齐填充部分来一起保证。

问题二:

步骤4中是如何从堆中划分内存的?

堆中划分内存有两种方法:指针 和  空闲列表。使用哪种方式取决于堆是否是规整的(堆是否能规整取决于使用的垃圾回收算法)。

规整的意思是说堆中使用过的内存和空闲内存有明显的划分界线,而不是混在一起的。

如果是规整的,那么就可以使用指针法,在使用过的内存和空闲内存的分界点用一个指针表示,分配内存时只要将指针向空闲内存方向移动一段与对象内存大小相等的距离。

如果不是规整的,那只能使用空闲列表,空闲列表是指虚拟机维护一个列表,记录哪些内存块是使用过的哪些是空闲的,分配内存时从列表中选择一块满足对象大小的内存块。这里如何选择内存块,估计就是学生时代学的操作系统讲的那些内容了,如何保证内存碎片较少之类的(后续整理)

hotspot使用的应该是指针

分配内存的时候还涉及到并发的问题,两种解决方式:

1 对分配内存这种操作进行同步处理,CAS保证操作的原子性

2 本地线程分配缓冲TLAB,预先为每个线程分配一小块内存TLAB,需要内存时各线程先在自己的TLAB上分配,当TLAB不够用的时候才会需要同步。

CAS:

简单描述下,大体采用的是乐观锁的思想,不使用锁,多个线程去改同一个变量时,都可以尝试去改,只会有一个线程成功,失败的线程也会立刻得到反馈,不会阻塞。

CAS中有三个变量,内存中的值V,预期原值A,新值B,每个线程尝试去改变量的时候,先判断A和V是否相等,如果相同,则将B更新到内存,否则更新失败。


Crystal_dan
34 声望0 粉丝