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验证程序没有调通,下次调通再补上说明。

 

 

 

猜你喜欢

转载自blog.csdn.net/huzhiliayanghao/article/details/106876053