对象的创建
这里指普通 Java 对象,而非数组 和 Class对象等。
1.创建对象的过程:
new ---> 到常量池中检查是否存在一个类的符号引用 ---> 如果有,检查这个符号引用代表的类是否已被加载、解析、初始化 ---> 没有,则执行类加载过程。
2.分配对象
类加载完毕后,为新生对象分配内存。
对象所需内存大小在类加载完成后便完全确定。分配空间。即,从JVM堆中划出一块确定大小的内存空间。
3.分配方法
有两种分配方法:
1.指针碰撞:
使用这种方式的前提是,内存是规整的。
左边是空闲的空间,右边是已使用的内存空间,用一块,就往左边移一块,就像秤砣在称中间移动一样。
2.空闲列表
内存不规整,此时不能使用指针碰撞。JVM 就需要维护一个列表,记录哪些空间可用并给对象。
堆内存是否规整决定了使用哪种分配方法。
而堆是否会规整则由GC是否带有压缩整理功能决定。
4.避免并发操作同一片内存的问题
并发时,A线程 拿着指针在为对象分配 0x111111 这片空间,分配动作执行到一半,B线程 也进来了拿着同一个指针在同一个地址上分配空间。这就出现了问题。
解决方案:
1.CAS 配置失败重试的方式保证更新操作的原子性。
2.为每个线程开一小块内存空间,称为本地内存分配缓冲(TLAB)。线程在自己的TLAB是分配。
5.初始化
当分配完成后,JVM将分配到的内存空间开始进行初始化为 0 值(不包括对象头),0值就是数学中的0。如果是TLAB方式,提前到TLAB中分配时进行。
这就是使用对象时,程序访问某些字段的数据类型默认有0的原因。就可以不用赋值也可以使用。
6.必要设置
接下来JVM对对象进行必要设置。
设置如:对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、GC分代年龄等。
这些信息存放在对象头中。
对JVM来说,对象已分配完成,一个新对象就此产生。
但从 java 程序的角度来说对象创建才刚开始。调用 init 方法前,所有字段都是默认的0。执行init方法,对象进行初始化,这样一个真正可用的对象才算完全产生。
网友评论