流程
类加载检查
虚拟机在接收一条new指令的时候,会检查该指令所代表的类的符号引用能否在常量池中找到,并且校验该类是否已经加载、验证、准备、解析、初始化;如果没有则必须经过类加载的过程将类加载进内存。
new指令对应到java上讲是创建对象的方式,如:new对象、对象克隆、对象序列化等。
分配内存
在类加载检查之后,虚拟机会为这个加载的类对象在堆中分配一块内存
内存划分的方法
- 指针碰撞:若java中内存分为两块,一块是使用过的,一块是空闲的,中间有一个指针隔开,当新的对象创建后分配内存时,只需要指针向空闲的内存空间移动和新对象一样大小的内存区域即可。
- 空闲列表:若java中内存是无序杂乱存放的,那就需要一个空闲列表来记录那部分的内存是空闲的,在新对象分配时,从列表中找一块足够大的空间分配给对象即可,同时也要更新空闲列表。
比较:从分配的角度来看,相比空闲列表,指针碰撞对内存的利用率应该是更高的;而空闲列表可能会产生一定的内存碎片。
解决并发的方法
- CAS:虚拟机采用CAS配上失败重试的方式保证更新操作的原子性来对分配内存空间的动作进行同步处理。
- 本地线程分配缓冲(TLAB):以线程的维度进行分配,在堆中为每一个线程预先分配一块内存。通过XX:+/ UseTLAB参数来设定虚拟机是否使用TLAB(JVM会默认开启XX:+UseTLAB),XX:TLABSize 指定TLAB大小
初始化
对类中的成员变量进行一个默认值的赋予。
设置对象头
在初始化之后,虚拟机对对象进行必要的设置,HotSpot中的对象头包含两部分,存储对象的运行时数据区和类型指针;其中运行时数据区包含哈希码、GC分代年龄、锁状态、对象持有的锁ID、偏向时间等,而类型指针是指堆中的对象所指向方法区(元空间)的类信息。
执行init方法
对类中的属性赋值
指针压缩
什么是指针压缩
在对象的创建过程中,将指针进行压缩,减少加载的类在内存中占用的空间。
使用指针压缩的原因
- 在64位的系统中,一个对象所占用的字节数是8,相比32位下系统所占用的4个字节,在对象创建完成就加大了内存的开销。
- 使用大指针在主内存和缓存之间移动数据,会占用较大的宽带,一定程度上加大GC的次数
指针压缩怎么使用
- jdk1.6 update14开始,在64bit操作系统中,JVM支持指针压缩
- jvm配置参数:UseCompressedOops,compressed压缩、oop(ordinary object pointer)对象指针
- 启用指针压缩:XX:+UseCompressedOops(默认开启),禁止指针压缩:XX:UseCompressedOops