Java对象在内存中的布局
先看两个问题:
1 对象的创建过程?
Object t = new Object();
首先创建对象的时候,会先检查对象的class类有没有加载过,如果没加载过就执行类加载过程
class loading(加载)
通过一个类的全限定名来获取类的二进制字节流
并未指定总哪获取,怎么获取。所以字节流可以是存储在硬盘上的文件,可以是运行时动态生成的二进制字节流,可以是有其他文件生成的(JSP对应的class文件)等等
将字节流代表的静态存储结构转化为方法区的运行时数据结构
在内存中生成一个代表这个类的Class对象,作为方法区这个类的访问入口
class linking(verification、preparation、resolution)
Verification (验证)
校验装载的class文件是否符合JVM规范
Preparation(准备)
将class文件的静态变量赋默认值
如:
static int i = 8 ;
这里会给i赋值0,而不是赋值8。
Resolution(解析)
将类、方法、属性等符号引用解析为直接引用
对class文件常量池中各种符号引用进行解析,转成指针,偏移量等内存地址的直接引用
class initializing(初始化)
给类静态变量设置初始值,同时执行静态语句块.
申请对象内存
成员变量赋默认值
给类成员变量 比如 int i =8;
将i赋值为0; i=0;
调用构造方法
成员变量顺序赋初始值
i =8;
执行构造方法
2 对象在内存中的存储布局?Object o = new Object()在内存中占用多少字符?
对象的大小以及内存布局与虚拟机的实现和设置有很大关系,所以先查看虚拟机的默认配置信息,观察虚拟机配置
java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize 初始的堆大小
-XX:MaxHeapSize 最大的堆大小
-XX:+UseComparessedClassPointers 和对象头有关系
-XX:+UseCOmparessedOops 和对象内存布局有关系
-XX:+UseParallelGC 和GC有关系
java数据类型的分类
java里面数据类型主要分为原生类型,类,接口,数组这几种。原生类型包括了int、long、double、char、byte等原生类型。原生类型对应的包装类型如Integer、Long、Double这些在java里面归类到类(class)里面,这里为了描述方便把接口(interface)也归类到类(class)里面。所以总的来说java的数据类型主要归为三类原生类型,类(class),数组。其中只有类和数组在java虚拟机里面是对象的形式的创建的,所以我们说的对象通常就是指类和数组的实例
对象的组成
根据java虚拟机规范里面的描述:java对象分为三部分:对象头(Object Header), 实例数据(instance data),对齐填充(padding)。如图:
下面我们以对象(Ojbect)为例分析每一部分组成。数组与对象类似,只是对象头部分多了数组长度Length的存储长度为4字节。
对象头(Object Header):
从图片上得知对象头分为两部分:Mark Word 与 Class Pointer(类型指针)。
Mark Word存储了对象的hashCode、GC信息、锁信息三部分,Class Pointer存储了指向类对象信息的指针。在32位JVM上对象头占用的大小是8字节,64位JVM则是16字节,两种类型的Mark Word 和 Class Pointer各占一半空间大小。
下面是用一张图展示 32位JVM上对象头的内存分布,方便理解。
64位
ClassPointer指针
在64位JVM上有一个压缩指针选项-ClassPointer指针:-XX:+UseCompressedClassPointers 为4字节 不开启为8字节。开启之后Class Pointer部分就会压缩为4字节,此时对象头大小就会缩小到12字节。
实例数据(instance data):
引用类型:-XX:+UseCompressedOops 为4字节 不开启为8字节 Oops Ordinary Object Pointers
Padding对齐,8的倍数
这个是可以通过程序验证的,今天idea验证程序没有调通,下次调通再补上说明。