new Object()的那些事 基于 hotspot jvm
1、Object o = new Object() 到底做了什么
Java虚拟机为我们申请一块地址---->并初始化内容----->将对象的开始地址作为指针返回给o,也就是o引用了(new Object())
2、如图 1,那jvm给我们生成的对象里面到底存了些什么东西呢?
2.1、图2中那整个地址每个部分到底的大小是多少呢,markword里面的每部分的作用及大小又怎么来区分和计算呢
图3
CMS(Concurrent Mark Sweep):GC标记清除算法的标识(初始标记>>并发标记>>重新标记>>并发清除如图)
2.2、那对象的每块大小又该如何计算呢
图4
如图4
A:Markword jvm设计成 8byte 也就是 64bit(64位)
B:type point 指针类型为4byte (32个字节,这个主要是又jvm配置而来的)
C:instance field 成员变量的大小分为基本类型和引用类型
c1:引用类型:4byte
c2:基本类型int--->4byte,float--->4byte ,char---->2byte,
double---->8byte,boolean--->1byte(后面会进行内部对其,填充一个1byte)
D:padding = 8 - (markword+type point+instance field)% 8+markword+type point+instance field
3:jvm新建的对象的内存一定是在堆上么
图5
如图5对象具体分配的策略
I、对象逃逸分析指当前的对象是否在别的地方存在引用,例如别的栈帧里面有指向该对象的指针,如果有视为对象逃逸,能够逃逸不能分配在栈里面,因为当前程序执行完,栈帧弹出对象就释放了。不能逃逸直接分配在栈里面,方便对象的释放,不需要经过GC
II、为什么堆里面要分为老年代,新生代(Eden)。因为堆里面的对象需要靠GC来进行垃圾回收,新生代采用的是标记复制算法来进行回收
图6
(标记复制算法)
标记复制算法针对大对象来说复制的成本太高效率太低,所以大对象会分配的老年区,而老年区使用的是标记清除算法
图7(标记清除算法)
标记清除算法不需要复制对象只是将标记需要清除的对象清除,这样就解决了大对象GC成本高的问题。那为什么新生代,老年代不使用同一种算法?
注:新生代存放很多小对象,如果使用标记清除算法,GC的时候会产生很多的内存碎片(也就是找不到一整块连续的内存空间)碎片太严重后续如果需要申请一整块,但是又找不到就出问题了。
III、为什么堆里面的新生代又分为Eden快分区,和Eden慢分区?
a:TLAB(Thread Local Allocation Buffer)线程本地分配缓冲区,叫做Eden快分区,意思就是jvm给每个线程在堆里面的新生代划分一块专属于线程的内存区域,在这个区域里面只有属于他的线程能够使用,这样的话,当线程需要创建对象,使用内存的时候不需要和别的线程竞争,能够快速分配到。
b:Eden慢分区也就是多个线程共用的区域,这块区域存在线程竞争分配效率会比TLAB低
最后附上一张hotspot jvm结构简图