对象的创建过程
加载
连接(验证、准备、解析)
初始化
申请内存
成员变量赋默认值
调用构造函数方法<init>,成员变量赋初始值,执行构造函数语句
对象在内存中的布局
对象头
- 普通对象 markword、classpointer
- 数组对象 markword、classpointer、arraylength
- markword 8byte、classpointer -XX:+UseCompressedClassPointers开启4byte 否则8byte
arraylength为4byte
实例数据
- reference -XX:+UserCompressedOops开启为4byte,否则8byte
对齐填充
markword
对象的状态包括无锁,偏向锁,轻量级锁,重量级锁,GC标记信息5中状态,所以锁标志位是3位
markword可以包含hashcode(如果有调用,gc分代年龄,锁状态信息,当前线程指针,当前线程LR指针,当前线程互斥量指针,当前线程cms过程标记信息。
当一个对象调用过identifyHashCode之后,不能进入偏向锁状态
对象怎么定位
直接指针,句柄池
直接指针访问速度快
句柄池,方便垃圾回收,当对象移动的时候,只需要修改句柄的指针就可以
对象内存分配过程
ew对象,可能在栈、TLAB、Eden、Old区四个地方。
TLAB: Thread Local Allocation Buffer线程本地分配缓冲池,Jvm在内存新生代EdenSpace开辟一块内存,线程私有,约占Eden的1%,所以无法分配大对象。
过程中的参数:
-XX:+DoEscapeAnalysis 开启逃逸分析
-XX:+UseTLAB 开启TLAB
-XX:TLABWasteTargetPercent 设置TLAB占Eden区比例
-XX:+EliminateAllocations 开启标量替换
-XX:+PrintEliminateAllocations 打印标量替换信息
-XX:PretenureSizeThreshold 对象进入老年代阀值
对象内存分配方式
指针碰撞:Serial、ParNew等带Compact过程的收集器,假设Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”(Bump the Pointer)
空闲列表:CMS这种基于Mark-Sweep算法的收集器
如果Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”(Free List)
内存分配并发问题
栈和TLAB不存在,Eden和Old采用cas方式解决
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。