java中的对象内存分配和访问

对象的创建

java中对象遇到new命令会在堆上分配内存,有2种方式分配内存,如果gc回收具有压缩选项,那么就采用指针碰撞。

指针碰撞,如果内存是规整的,已经被使用的在一边,未使用的在一边,中间用指针分割,如果需要创建对象,就移动指针,移动的大小和创建的对象大小一致。

另一种是采用"空闲列表",gc回收不具有压缩选项,虚拟机会维护一个"空闲列表",记录哪些内存是可用的,需要创建对象,就在列表中寻找哪些内存可以用来创建对象。

由于对象的创建在虚拟机中是十分频繁的,所以存在线程不安全的情况。为了避免发生这种事情,有2种方式保证创建对象的线程安全。一种是分配内存的操作是同步的,这样就保证了同一时刻只进行一个对象的内存分配。另一种是分配内存的操作按线程划分在不同区间内。虚拟机开始时会给每个线程分配本地线程缓冲区域,如果一个线程需要更大的内存,就会在该线程内分配内存。

对象在内存中的分配

对象在内存中分为3个部分,对象头,实例数据和对其填充。

对象头包含2个部分,对象运行时数据和类型指针。如果是数组,还会有一个部分包含数组的长度。

实例数据就是实例化对象里的数据。

对其填充,虚拟机要求java对象的开始地址必须是8字节的整数倍,就是大小是8字节的整数倍(深入理解jvm里描述的)。对象头是8字节的,如果实例数据部分不满足8字节的整数倍,那么对其填充的作用就是补齐,形成整数倍。

对象在内存中的访问定位

java对象会在栈上存在指向对象的指针。指向对象的方式有2种。一种是通过句柄,另一种是直接指针。

采用句柄指向对象,首先栈中的reference会指向句柄池,句柄池内包含指向实例对象的指针和类型对象指针。这种方式的好处是,实例对象的地址改变只需要更新句柄池中的对象内容即可。

直接指针,顾名思义,就是直接指向堆中和方法区中的实例对象和类型对象了。这种方式的好处就是速度很快,不需要通过中间方式寻找对象。

猜你喜欢

转载自www.cnblogs.com/ter-yang/p/9685987.html