JVM-对象创建、访问、内存布局
-
Java的对象创建
虚拟机遇到一条新的指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号,并且检查这个符号引用代表的类是已被加载,解析和初始化过,如果没有先执行相应的类加载过程。
在类加载检查通过后,为新生对象分配内存。对象所需内存的大小在类加载完成后便可以完全确定,为对象分配空间的任务等同于把一块确定大小的内存从java的堆中划分出来。
1.指针碰撞
假设Java的内存绝对规整,所有已使用的内存在一遍,另一边是未使用的,中交放一个指针作为分界点的指示器,那所分配内存就仅仅指针向空闲那边挪到一段与对象大小相等的距离,图中虚线位置,这种方式称为“指针碰撞”。
2.空闲列表
如果Java的堆中的内存并不是规整的,已使用的和未使用的互相交错,没有办法进行简单的指针碰撞,虚拟机就必须维护一个表,记录哪些内存块是可以用的,并且找一个足够大的内存空间分配实例对象;并更新列表里面的记录,这种分配方式称为“空闲列表”。
选择哪种分配方式由Java的堆是否规整决定,二Java的堆是否规整由所采用的垃圾收集器决定。
-
对象内存布局
1.对象头
第一部分:存储对象自身的运行时数据,如哈希码,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳等。
另一部分:类型指针,即对象指向它的元数据指针,虚拟机通过这个指针来确定这个对象是哪个类的实例如果对象是一个数组,那在对象头中还必须有一块用于记录数组长度。的数据。
2.实时数据
对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。
3.对齐填充
占位符作用,hotSpot VM的自动内存管理系统要求对象的大小必须是8字节的整数倍。二对象头部分正好是8字节的倍数,当实例数据部分没有对齐时。就需要通过对齐填充来补全。
-
对象访问定位
Java的程序通过栈上的引用数据来操作堆上的具体对象。
目前主流的访问方式有使用句柄和直接指针两种。
1.句柄
如果使用句柄访问的话,那么java的堆中将会划分出一块内存来作为句柄池,参考中存储的就是对对象的句柄地址,而句柄中包含了对象实例数据与类型数据各种的具体地址信息。使用句柄的最大好处就是参考中存储的是文档的句柄地址,在对象移动的时候只会改变句柄中示例数据指针,而本身不需要修改。
2.直接指针
如果使用直接指针,参考中存储的直接就是对象地址,最大好处就是速度快,节省了一次指针定位的时间开销.Sun hotSpot使用的是直接指针。