前提回顾
建议大家从[【Java技术专题-JVM研究系列(39)Java各种类型对象占用内存情况分析(上)】]开始学习比较好,这样子会有一个承接和过度。根据前面的学习的内存占用计算规则,可以计算出一个对象在内存中的占用空间大小情况,下面举例分析下Java中的Enum, ArrayList及HashMap的内存占用情况,读者可以仿照分析计算过程来计算其他数据结构的内存占用情况。
注: 下面的分析计算基于HotSpot Jvm, JDK1.8, 64位机器,开启指针压缩。。
对象头
这里只关注其内存占用大小。在64位机器上,默认不开启指针压缩(-XX:-UseCompressedOops)的情况下,对象头占用12bytes,开启指针压缩(-XX:+UseCompressedOops)则占用16bytes。
实例数据:
对象引用(reference)类型在64位机器上,关闭指针压缩时占用8bytes, 开启时占用4bytes,一般指的是局部变量表或者操作数栈中的reference类型或者针对于成员变量情况下的地址引用(shallow size)。
注: 下面的分析计算基于HotSpot Jvm, JDK1.8, 64位机器,开启指针压缩。
枚举类
创建enum时,编译器会生成一个相关的类,这个类继承自
java.lang.Enum
。Enum类拥有两个属性变量,分别为int的ordinal和String的name, 相关源码如下:
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
/**
* The name of this enum constant, as declared in the enum declaration.
* Most programmers should use the {@link #toString} method rather than
* accessing this field.
*/
private final String name;
/**
* The ordinal of this enumeration constant (its position
* in the enum declaration, where the initial constant is assigned
* an ordinal of zero).
*
* Most programmers will have no use for this field. It is designed
* for use by sophisticated enum-based data structures, such as
* {@link java.util.EnumSet} and {@link java.util.EnumMap}.
*/
private final int ordinal;
}
以下面的TestEnum为例进行枚举类的内存占用分析
public enum TestEnum {
ONE(1, "one"),
TWO(2, "two");
private int code;
private String desc;
TestEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
这里TestEnum的每个实例除了父类的两个属性外,还拥有一个int的code及String的desc属性,所以一个TestEnum的实例本身所占用的内存大小为:
12(header) + 4(ordinal) + 4(name reference) + 4(code) + 4(desc reference) = 28(padding) -> 32 bytes.
总共占用的内存大小为:
按照上面对字符串类型的分析,desc和name都占用:48bytes。
所以TestEnum.ONE占用总内存大小为:
12(header) + 4(ordinal) + 4(code) + 48 * 2(desc, name) + 4(desc reference) + 4(name reference) = 128 (bytes)
ArrayList
ArrayList实现List接口,底层使用数组保存所有元素。其操作基本上是对数组的操作。下面分析下源代码:
底层使用数组保存数据:
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
构造方法
ArrayList提供了三种方式的构造器,可以构造一个默认的空列表、构造一个指定初始容量的空列表及构造一个包含指定collection元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列。
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMP