对象的创建过程
class loading
class linking
class initializing
申请内存
成员变量赋默认值
调用构造方法
对象内存布局
可以分为两种:普通对象、数组对象
普通对象:
- 对象头:markword 8
- ClassPointer指针:-XX:+UseCompressedClassPointers 为4字节 不开启为8字节
- 实例数据:引用类型:-XX:+UseCompressedOops 为4字节 不开启为8字节 Oops Ordinary Object Pointers
- Padding对齐:8的倍数
数组对象:
- 对象头:markword 8
- ClassPointer指针:-XX:+UseCompressedClassPointers 为4字节 不开启为8字节
- 数组长度:4字节
- 数组数据
- Padding对齐:8的倍数
一个Object对象的大小
//一个Object占多少个字节
// -XX:+UseCompressedClassPointers(关闭压缩) -XX:+UseCompressedOops(普通对象指针)
// Oops = ordinary object pointers
对象头8+class指针(默认把压缩指针打开,8个字节压缩成4个字节)+对齐4=16
private static class P {
//8 _markword
//4 _class pointer
int id; //4
String name; //4 本来应该是8个字节,但是开启了-XX:+UseCompressedOops
int age; //4
byte b1; //1
byte b2; //1
Object o; //4 普通对象指针
byte b3; //1
}
Hotspot开启内存压缩的规则(64位机)
-
4G以下,直接砍掉高32位
-
4G - 32G,默认开启内存压缩 ClassPointers Oops
-
32G,压缩无效,使用64位 内存并不是越大越好(^-^)
Markword对象头
不同状态下的markword是表示不同的内容的,这个不是固定的。
- synchronized有一个锁升级的过程,其中偏向锁是用一位来表示偏向模式,下次这个线程再进来就不需要加锁,其实偏向锁是用三位来表示。
- 对象的hashcode显示的前提是调用了未被重写hashcode()方法才会产生,重写过的hashcode方法计算的结果不会保存在这里。
- 后面的JVM新生代在经过15次GC之后会变成老年代,为啥是15次?是因为分代年龄那里用4位来表示,1111最大为15.
- 当一个对象计算过identityHashCode之后,不能进入偏向锁状态,因为偏向锁的那个位置被占
对象定位
- 句柄池
- 直接指针
对象分配
- 栈上分配,栈一弹出对象就没了
- 栈不能分配,而且对象很大,分配到OLD区最后由FGC回收
- 对象不大,看是否可以线程本地分配,不可以就分配到Eden区,GC到了一定的分代年龄之后进入OLD区,最后由FGC回收