从类加载到对象分配内存过程:

1、什么是TLAB?
从内存模型角度,对Eden区域继续进行划分,JVM在Eden空间内为每一个线程分配了一个私有缓存区域。
多线程同时分配内存时,使用TLAB可以避免一系列的非线程安全问题,同时还能提升内存分配的吞吐量,这种内存分配方式称为快速分配策略。
TLAB 在 JVM 中默认启用(通过参数 -XX:+UseTLAB
控制)。线程启动时,JVM 从 Eden 区划分一块内存作为其 TLAB。初始大小由 JVM 自适应计算(通常占 Eden 区的 1%),也可通过参数 -XX:TLABSize
手动设置。
2、创建对象的方式?
- 通过new 关键字
- Class的newInstance()(官网不建议使用)
- Constructor的newInstance(Xxx)
- 使用clone()
- 使用反序列化
- 第三方库Objectsis
3、创建一个对象经历哪些步骤?
-
判断对象对应的类是否加载、链接、初始化
-
为对象分配内存:根据内存是否规整,分配方式有所不同,
- 如果内存规整,则采用指针碰撞的方式;
- 如果内存不规整,则需要维护一个列表,按空闲列表分配
-
处理并发安全问题:有两种方式处理并发问题,
- 采用CAS+失败重试保证更新的原子性
- 为每一个线程预分配一块TLAB
-
初始化分配的空间: 为所有的属性设置默认值,保证对象实例字段在不赋值可以使用
-
设置对象的对象头
-
执行Init方法进行初始化(包括:构造器,实例代码块,属性显示赋值)

4、一个对象在内存空间长什么样?
- 对象头(Header)
- 实例数据(Instance Data)
- 对齐填充(Padding)
对象头主要包含两部分:运行时元数据、类型指针,如果是数组,还需要记录数组的长度。运行时元数据主要包含哈希、GC分代年龄和锁相关信息。类型指针指向类的元数据。
实例数据包含了父类变量和自己类变量数据
对齐填充是非必要的

看下面一段代码,在内存空间是如何分布的
代码:
arduino
package com.test.jvm;
public class InstanceHeapTest {
public static void main(String[] args) {
Customer cust = new Customer(1, "张三", new Account(1, "张三"));
}
}
class Customer {
private int id;
private String name;
private Account acct;
public Customer(int id, String name, Account acct) {
this.id = id;
this.name = name;
this.acct = acct;
}
// get set 方法省略
}
class Account {
private int id;
private String name;
public Account(int id, String name) {
this.id = id;
this.name = name;
}
// get set 方法省略
}
内存分布示意图:
