我们在Java单个对象内存布局中讲解了单个简单的Java对象所占内存的大小的计算。那么这篇文章主要是讲解复杂Java对象所占内存大小的计算,我们把继承、复合的对象称为复杂对象

继承对象

class Parent {
protected int x; // 4字节
protected int y; // 4字节 protected boolean flag; // 1字节
} class Child extends Parent {
private int z; // 4字节
} public class ExtendsObjectSizer {
public static void main(String[] args) {
System.out.println("继承对象的大小为:" + ObjectSizeFetcher.sizeOf(new Child()) + "字节");
}
}

  

然后重新打包,执行如下的命令:

## 没有开启指针压缩功能
java -XX:-UseCompressedOops -javaagent:ObjectSizeFetcherAgent-1.0-SNAPSHOT.jar com.twq.ExtendsObjectSizer

得到的结果如下:

可以看出new Child()的内存大小为40字节,那么这个40字节是怎么来的呢?我们看下图:

40字节 = 16 + (4 + 4 + 1 + 7) + 4 + 7

## 开启指针压缩功能
java -XX:+UseCompressedOops -javaagent:ObjectSizeFetcherAgent-1.0-SNAPSHOT.jar com.twq.ExtendsObjectSizer

  得到的结果如下:

可以看出new Child()的内存大小为32字节,那么这个32字节是怎么来的呢?我们看下图:

32字节 = 12 + 4 + 4 + 1 + 7 + 4

总结:继承对象也只有一个对象头,继承对象所占内存的大小由4部分组成:

  1. 对象头
  2. 父亲属性所占内存大小,需要对齐补充至8的倍数
  3. 子类属性所占内存大小
  4. 对齐补充

复合对象

我们接下来看下复合对象所占内存大小,先看下如下代码:

class Employee {
private int age; // 4字节
private double high; // 8字节
} class Dept {
private int num; // 4字节 private Employee[] employees = new Employee[3]; public Dept() {
for (int i = 0; i < employees.length; i++) {
employees[i] = new Employee();
}
}
} public class CompositeObjectSizer {
public static void main(String[] args) throws IllegalAccessException {
System.out.println("复合对象内存的大小为:" + ObjectSizeFetcher.sizeOf(new Dept()) + "字节");
System.out.println("复合对象内存的总大小为:" + ObjectSizeFetcher.fullSizeOf(new Dept()) + "字节");
}
}

  然后重新打包,执行如下的命令:

得到的结果如下:

可以看出复合对象内存的大小为32字节 = 对象头16字节 + num属性4字节 + employees引用类型的大小8字节 + 对齐补充4字节

这个32字节也只是直接计算当前Dept对象占用空间大小,这个大小并没有包含数组employees中所有的Employee的内存大小,那么这个复合对象的总大小为176字节,这个大小包括了数组employees中所有的Employee的内存大小,也就是递归计算当前对象占用空间总大小。

递归计算复合对象占用的内存的时候需要注意的是:对齐填充是以每个对象为单位进行的,看下面这个图就很容易明白: 

根据上图,我们手动来计算一下new Dept()的总内存大小,分为3部分:

  • Dept实例对象本身的大小为:16 + 4 + 8 + 4 = 32字节
  • 数组对象employees的大小为:24 + 8 * 3 = 48字节
  • 3个Employee对象的大小为:3 * (16 + 4 + 8 + 4) = 96字节

所以内存总大小为:32 + 48 + 96 = 176字节

我们再来看下开启了指针压缩功能的复合对象内存的大小情况,我们执行如下的命令:

## 开启指针压缩功能
java -XX:+UseCompressedOops -javaagent:ObjectSizeFetcherAgent-1.0-SNAPSHOT.jar com.twq.CompositeObjectSizer

  

得到的结果如下:

可以看出复合对象内存的大小为24字节 = 对象头12字节 + num属性4字节 + employees引用类型的大小4字节 + 对齐补充4字节

在开启指针压缩功能的情况下,Dept复合对象的总大小为128字节,如下图:

根据上图,我们手动来计算一下new Dept()的总内存大小,分为3部分:

  • Dept实例对象本身的大小为:12 + 4 + 4 + 4 = 24字节
  • 数组对象employees的大小为:16 + 4 * 3 + 4 = 32字节
  • 3个Employee对象的大小为:3 * (12 + 4 + 8) = 72字节

所以内存总大小为:24 + 32 + 72 = 126字节

ArrayList

以下是ArrayList的部分源码:

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
protected transient int modCount = 0;
} public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L; /**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10; /**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object[] elementData; // non-private to simplify nested class access /**
* The size of the ArrayList (the number of elements it contains).
*/
private int size;
}

  

static变量属于类,不属于实例,存放在全局数据段。普通变量才纳入Java对象占用空间的计算,一个用于存放数组元素的Object[], 一个int类型的size,还有一个是父类中int类型的modCount。因此:

  • 在64位操作系统,且未开启指针压缩功能的前提下,new ArrayList<Integer>()的内存大小应为:对象头16字节 + 父类属性modCount大小4字节 + 对齐补充4字节 + 子类Object[]引用类型的8字节 + 子类int类型的属性大小4字节 + 对齐补充4字节 = 40字节
  • 在64位操作系统,且开启了指针压缩功能的前提下,new ArrayList<Integer>()的内存大小应为:对象头12字节 + 父类属性modCount大小4字节 + 对齐补充4字节 + 子类Object[]引用类型的4字节 + 子类int类型的属性大小4字节 + 对齐补充4字节 = 32字节

复杂Java对象所占内存的大小的更多相关文章

  1. 如何计算Java对象所占内存的大小

    [ 简单总结: 随便一个java项目,引入jar包: lucene-core-4.0.0.jar 如果是 maven项目,直接用如下依赖: <dependency> <groupId ...

  2. java中基本类型封装对象所占内存的大小(转)

    这是一个程序,java中没有现成的sizeof的实现,原因主要是java中的基本数据类型的大小都是固定的,所以看上去没有必要用sizeof这个关键字. 实现的想法是这样的:java.lang.Runt ...

  3. 4种方法教你如何查看java对象所占内存大小

    摘要:本文讲述4种查看java对象所占内存大小的方法 本文分享自华为云社区<查看java对象所占内存大小>,作者:xiewenci. 计算java对象所占内存大小 1.使用jdk8自带AP ...

  4. 如何获取一个Java对象所占内存大小

    新建一个maven工程 我们先在IDEA中新建一个名为ObjectSizeFetcherAgent的maven工程,如下图: 在maven项目中的pom.xml中新增一个打jar包的插件,如下: &l ...

  5. Java学习日记-2.3 基本数据类型和对象所占内存空间大小

    转自:http://www.newsmth.net/nForum/#!article/Java/324167

  6. JAVA数组所占内存大小的对比

    1.两个数据模型 第一个是基本类型数组,第二个使用的是Float对象数组 public class SummaryModel{ private float[] summaryData; public ...

  7. C# 能否获取一个对象所占内存的大小?

    今日,在项目重构的时候忽然想到一个问题,一个类哪些成员的增加,会影响一个类所占内存的大小?C#有没有办法知道一个对象占多少内存呢? 第一个问题:很快想到是类的非静态的字段.属性. 第二个问题:首先想到 ...

  8. 获取JAVA对象占用的内存大小

    介绍两种获取JAVA对象内存大小的方法. 第一种:Instrumentation 简介: 使用java.lang.instrument 的Instrumentation来获取一个对象的内存大小.利用I ...

  9. 一个Java对象到底占多大内存

    最近在读<深入理解Java虚拟机>,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存? 在网上搜到了一篇博客讲的非常好 ...

随机推荐

  1. Python MySQLdb 学习总结(转)

    转自http://www.cnblogs.com/coser/archive/2012/01/12/2320741.html 感谢@糖拌咸鱼 任何应用都离不开数据,所以在学习python的时候,当然也 ...

  2. 【转】Lombok介绍、使用方法和总结

    链接:http://www.yuanrengu.com/index.php/20180324.html 1 Lombok背景介绍 官方介绍如下: Project Lombok makes java a ...

  3. windows下大数据开发环境搭建(1)——Java环境搭建

    一.Java 8下载 https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下载之后 ...

  4. LeetCode 572. 另一个树的子树(Subtree of Another Tree) 40

    572. 另一个树的子树 572. Subtree of Another Tree 题目描述 给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树.s 的一个子树包括 ...

  5. LeetCode 513. 找树左下角的值(Find Bottom Left Tree Value)

    513. 找树左下角的值 513. Find Bottom Left Tree Value 题目描述 给定一个二叉树,在树的最后一行找到最左边的值. LeetCode513. Find Bottom ...

  6. 【C++札记】拷贝构造函数,浅拷贝和深拷贝

    一:拷贝构造函数 拷贝构造函数是一种特殊的构造函数,遵循如下的规则: 1.函数名和类名一致,没有返回值. 2.必须有一个参数,参数是本类型的一个引用变量. 3.拷贝构造函数可以访问参数对象的任意成员( ...

  7. poj 3744 题解

    题目 题意: $ yyf $ 一开始在 $ 1 $ 号节点他要通过一条有 $ n $ 个地雷的道路,每次前进他有 $ p $ 的概率前进一步,有 $ 1-p $ 的概率前进两步,问他不领盒饭的概率. ...

  8. hdu 1850 题解

    题目 题意:n堆扑克牌,每次可以取走一堆中任意张数的扑克牌,问先手胜利第一步有几种可能. 这一题如果除去后面一问就直接问先手赢还是后手赢,这就是一道简单的 $ NIM $ 博弈问题. 定理 $     ...

  9. git学习笔记 ---版本退回

    我们已经成功地添加并提交了一个readme.txt文件,现在,是时候继续工作了,于是,我们继续修改readme.txt文件,改成如下内容: Git is a distributed version c ...

  10. SpringBoot 常用配置 静态资源访问配置/内置tomcat虚拟文件映射路径

    Springboot 再模板引擎中引入Js等文件,出现服务器拒绝访问的错误,需要配置过滤器 静态资源访问配置 @Configuration @EnableWebMvc public class Sta ...