JVM系列(四) : 对象分配
1、JVM中执行字节码new指令时:
1.1、分配内存
分配策略有两种方式:(1)指针碰撞 当JVM内存区域是连续的规整的,所有用过的内存都放在一边,空闲的内存都放在另外一边,中间放着
指针作为分界点的指示器,再分配内存的时候,只需将指针移动对象大小的距离就可以
(2)空闲列表,当JVM内存区域不是连续的,需要一个空闲的列表记录那些是被占用、那些未被占用,通过列表来查找对象大小的内存进行分配
注:选择哪种分配方式由JVM内存是否规整决定,内存是否规整有垃圾回收算法决定
1.2、分配内存线程安全问题
二种方式:(1)CAS配上失败重试机制
(2) 本地线程缓冲机制,虚拟机设置参数-XX:UseTLAB 在线程初始化的时候,提前在Eden 区分配很小的一块内存区域(约占Eden 1%)
TLAB 只让每个线程有私有的分配指针,对象的内存空间还是共享的。
1.3、内存空间初始化
在对象分配内存后,需要初始化对象的实例变量,静态变量的初始默认值如:int 默认值是0, boolean 默认值是 false, String 默认值是null
1.4、对象头设置
对象内存空间初始完后,设置对象头信息,设置对象的hashcode、锁的标志、当前对象所属的类、对象的GC分代年龄等
1.5、对象初始化
执行构造方法初始化实例变量和静态变量的值
2、对象的内存布局
对象头、实例数据、对齐填充
对象头包含对象自身运行的数据,如:对象的hashcode、锁状态标志,线程持有的锁等
实例数据:对象中定义的实例变量和静态变量等各种类型的字段
对齐填充:对象都是8字节的整数倍,不够的用对齐填充
3、对象的访问方式
3、内存分配策略
堆分为新生代、老年代,新生代包括Eden、form、to区默认比例为8:1:1
堆中参数设置: 新生代大小:-Xmn10m
-XX:SurvivorRatio=8 表示Eden 和Survivor的比值 缺省为8 表示Eden:From:To=8:1:1
(1)对象优先在Eden 上分配
对象优先在Eden上分配,如果没有足够的内存空间、将触发一次minor GC
(2)大对象直接进入老年代
可以通过参数 -XX:PretenureSizeThreshold=4m 设置进入老年代对象大小,超过这个参数大小直接进入老年代,PretenureSizeThreshold参数只对Serial和ParNew两款收集器有效
(3)长期存活的对象进入老年代(对象的年龄超过15)
minor GC 一次,对象的年龄就增加一次,当对象的年龄增加到一定值(默认值时候15)是就直接进入老年代
(4)动态对象年龄判定(对象头中的年龄代别)
survivor 空间中相同年龄所有的对象大小的总和大于Survivor 空间的一半,年龄大于或者等于这个年龄的直接进入老年代
(5)空间分配担保
HandlePromotionFailure 设置不允许空间担保,需要进行Full GC 如果设置为允许担保则检查老年代最大连续可用的内存空间是否大于历次晋升到老年代对象的平均大小,如果大于尝试进行minor GC
如果担保失败,进行Full GC