对象与内存_深入JVM(二)

对象与内存

 

        简要的了解一下虚拟机中内存的使用细节,它们是如何创建、如何布局、如何访问的.

对象的创建

        (在java中,一个java类将会编译成一个class文件。在编译时,java类并不知道引用类的实际内存地址,因此只能使用符号引用来代替。比如org.simple.People类引用org.simple.Tool类,在编译时People类并不知道Tool类的实际内存地址,因此只能使用符号org.simple.Tool(假设)来表示Tool类的地址。而在类装载器装载People类时,此时可以通过虚拟机获取Tool类 的实际内存地址,因此便可以既将符号org.simple.Tool替换为Tool类的实际内存地址,及直接引用地址。)

        遇到一条new指令,首先先去 检查 ,检查这个指令的参数是否能在常量池中可以找到一个符号引用,并检查这个符号引用已被加载过 .

        然后,虚拟机将对这个新生对象分配内存 , 分配的内存大小在类加载后已经确定 .在堆中,不同区域内存分配的方式不同 , 两种内存分配方式 : 1.指针碰撞(需要连续规整的内存,通过指针向空闲区域移动一段与对象大小相对等的距离) 2.空闲列表 (维护了一个记录了内存使用状态的列表,动态的维护列表, 分配内存时从列表中找到足够大的空间划分给对象,不需要内存连续和规整)

        由于堆是线程共享的区域,因此高并发情况下,一个指针移动的操作都会有线程安全问题 ,虚拟机采用了 : 1.CAS+失败重试的方式来保证分配内存操作时的原子性. 2.采用TLAB(本地线程分配缓冲)区域来分配内存, 用完并分配新的TLAB时,再进行同步加锁操作,可保证原子性.

        内存分配完成后,虚拟机会将分配空间(除对象头区域)初始化为零值 , TLAB则在创建缓冲区域时将区域值清零,这也是为什么我们可以直接使用new出来对象的各个属性的值的原因.

        接下来,虚拟机将初始化对象头区域 , 将类的元数据,对象的哈希码,对象的GC分代年龄等信息,已规定格式,写入对象头区域.

对象的布局

                对象在内存中的储存布局可以分为3块区域 : 对象头 , 实例数据 和对其填充.

        对象头

                HotSpot虚拟机内存头包括两部分信息 : 1.储存对象自身的运行时数据,官方称为"Mark Word",这一部分储存了HashCode,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳等...

                2.类型指针,指向该对象的类元数据的指针,如果该对象是一个数组,那么在对象头中还有记录数组长度的信息

        实例数据

                是用来储存对象信息的有效数据区,即各字段的值 ,无论是定义的还是继承的字段,信息都会在这个区域 . 各字段信息在该区域的排列顺序受分配策略影响(父类变量在前,相同宽度的数据类型会排列在一起...)

        填充数据

                对象的总大小必须是8字节的倍数,实例数据区不足8字节的,要求填充到8字节.

对象的访问定位

                HotSpot是使用直接指针来访问对象的.

猜你喜欢

转载自blog.csdn.net/start_lie/article/details/81193080
今日推荐