划分对象两种方式:
1.指针碰撞: Java堆内存规整的情况下使用
2.空闲列表:Java堆内存不规整的情况下使用
JVM中分配对象:
本地线程分配缓冲
Thread Local Allocation Buffer, TLAB (Eden 1%)
栈----堆中预先分配一块很小私有区域。
CAS比较和交换,确保原子性问题。
对象内存布局
在HostSpot虚拟机中,对象在内存中存储布局可以分为3个部分:对象头(Header)、实例数据(Instance Data)和对其填充(Padding)。
对象头:包括两部分信息,
第一部分存储本身运行时数据,如哈希码(hashcode)、GC分代年龄、锁状态标志、线程持有锁、偏向线程ID、偏向时间戳等。
另一部分是类类型指针,及对象指向类元素的指针,虚拟机通过这个指针确定这个类是哪个对象的实例。
对其填充:对象的大小必须是8个字节。实例数据7个字节 填充1个,1个填充7个
对象访问方式
1.句柄(特殊的指针),移动方便,访问效率低
2.直接指针(HotSpot中使用)
堆内存分配策略
新生代Eden区
Survivor(from)区,设置Survivor是为了减少送到老年代的对象
Survivor(to)区
设置两个Survivor区是为了解决碎片化问题(复制回收算法)
1.对象优先在Eden区分配
-Xms:20m堆空间20m
-Xmx:20m 堆最大空间20m
-Xmn:10m 新生代(Eden区)10m
-XX:+PrintGCDetails 打印GC日志
-XX:+UseSeriolGC 一个垃圾回收器种类
-XX:PretenureSizeThreshold=2m 超过2M的对象可以直接进入老年代
注:大多数情况对象是在Eden区分配,当Eden区空间不足,虚拟机将会发起一次Minor GC。
2.大对象直接进入老年代
目的:1.避免大量内存复制2.避免提前进行垃圾回收,明明内存有空间分配
3.长期存活对象进入老年代
Eden区8m占满,再分配1m对象,Eden区会发生MinGC.
存活对象进入from区,年龄+1,再来垃圾回收则进入to区,年龄再+1。
再次进行垃圾回收,对象返回from区,年龄再+1, from和to区反复,因为from和to区采用复制回收算法的原因。
年龄达到15岁(默认),属于长期存活对象,进入老年代。
4.动态年龄判断
from和to区年龄所有对象大小加起来大于from年龄的一半,年龄大于等于该年龄的对象就可以直接进入老年代。
5.空间分配担保
HandlePromotionFailure, 不用考虑老年代空间不够,不用考虑发生FullGC,如果担保失败或内存不够也会进行一次FullGC
FullGC:当老年代空间不足时候,有from或to区升级进入老年代的时候,将会执行FullGC