1.当遇到new指令时,检查是否能在常量池定位到一个类的符号引用,检查这个符号引用代表的类是否已被加载、解析、初始化过。若没有,将执行类的加载过程。
2.为对象分配内存。分配多大在类加载完成后就已得知。
- 分配方式
- 指针碰撞:假设java堆上内存规整,一边是空闲的内存,一边是已使用过的内存。那么分配内存的 *** 作就是,把指针向空闲内存的方向移动一段与对象大小的距离。
- 空闲列表:维护一个记录可用内存块的表,在分配时寻找一块足够大的空间给对象实例,并更新记录。
解决并发情况下线程不安全的情况:
- 内存分配:虚拟机采用CAS(比较交换)+失败重试的机制保证更新 *** 作的原子性
- TLAB:为每个线程在Java堆上分配一个一小块区域当做缓冲区,只有这个缓冲区用完时,分配新的缓冲区时才进行同步锁定。
3.将分配到的空间(不包括对象头)初始化为零值(使用了TLAB,这步会在TLAB分配时进行)。这步使对象实例字段在Java代码中可以不赋初始值就可以直接使用。
4.对对象进行设置,如对象是哪个类、哈希码、GC分代年龄等。这些信息都在对象头中。
对象信息由三部分组成:对象头、实例数据、对齐填充。
对象头对象头中含两类信息:
- 第一类:用于存储对象自身的运行时数据:如哈希码、GC分代年龄、锁状态标志、持有的锁、偏向时间戳、偏向线程ID等。
- 第二类:类型指针,指向对象的类型元数据指针-----类。但是虚拟机实现不一定都会在对象类型保留类型指针。即查找对象元数据信息不一定通过对象本身。
存储父类继承下来的和子类中定义的字段。
对齐填充非必然,使对象大小为8字节的整数倍。
三、对象的访问定位Java程序会通过栈上的reference类型数据 *** 作堆上的数据。目前有两种主流的实现方式。
句柄访问Java堆会分配一块内存存作为句柄池存放句柄,对象移动时(垃圾收集普遍发生),reference(存储句柄地址)不改变,只改变句柄存放的内容。
reference直接存储对象地址,好处是节省一次指针定位的时间开销。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)