Java对象占用内存分析

Java常见对象的内存占用分析,并计算对象的深堆和浅堆大小。

Posted by Lance Lee on Monday, February 22, 2021

TOC

零 环境说明

64位机器,开启指针压缩(JDK1.8默认开启)。

一 基本数据类型

数据类型 字节数 备注
byte 1
short 2
int 4
long 8
float 4
double 8
boolean 1
char 2 (Java使用Unicode编码,固定2字节)

二 数组

数组的对象头相较于对象,额外多了4字节的数组长度。因此对象头大小为16字节。

数组对象头 = Mark Word + Klass Word + array length = 8 + 4 + 4 = 16字节

数组实际内存大小 = 对象头 + 数组元素 + 对齐填充字节 = 16 + 数组元素数据类型 * 数组长度 + padding

由于不同的类型字节不同,对齐字节数也不同。

以一个存有4个元素的int数组为例。

int[] arr = new int[4];
实际内存大小 = 16 + 4 * 4 + 0 = 32字节

不需要填充对齐字节,因此浅堆和深堆都是32字节。

三 对象

对象的对象头为12字节。

Note:对象大小不包括里面的静态变量,静态变量属于Class对象成员。

3.1 数据包装类

对象 字节数 对齐填充字节 实际内存大小 备注
Byte 13 3 16
Short 14 2 16
Integer 16 0 16
Long 20 4 24
Float 16 0 16
Double 20 4 24
Boolean 13 3 16
Character 14 2 16

没有包含对象类型的属性,所以实际内存大小等于深堆,也等于浅堆。

1 Integer

Integer为例进行分析,Integer对象的属性其实只有value一个,其他都是类变量。

private final int value;
实际内存大小 = 对象头 + value属性 + 填充对齐字节 = 12 + 4 + 0 = 16字节

不需要填充对齐字,深堆和浅堆大小,都是16字节。

3.2 String对象

String对象有以下属性

char[] value
int hash
实际内存大小 = 对象头 + 属性 + 填充对齐字 = 12 + 4 + 4 + 4 = 24字节

需要填充对齐4字节,因此浅堆大小 = 24字节。

下面以字符串aaa为例,计算深堆大小。

String str = new String("aaa");

只需要额外加上char数组的实际内存大小。

char数组实际内存大小 = 对象头 + 数组元素 + 填充对齐字节 = 16 + 3 * 2 + 2 = 24字节

因此数组深堆大小为24 + 24 = 48字节。

3.3 Class对象

1 Object.class

Object对象有以下静态属性

java.lang.reflect.Constructor cachedConstructor
java.lang.Class newInstanceCallerCache
java.lang.String name
java.lang.ref.SoftReference reflectionData
sun.reflect.generics.repository.ClassRepository genericInfo
java.lang.Object[] enumConstants
java.util.Map enumConstantDirectory
java.lang.Class.AnnotationData annotationData
sun.reflect.annotation.AnnotationType annotationType
java.lang.ClassValue.ClassValueMap classValueMap
int classRedefinedCount
对象 字节数 对齐填充字节 实际内存大小 备注
Object.class 456 40 496

2 Integer.class

java.lang.reflect.Constructor Class.cachedConstructor
java.lang.Class Class.newInstanceCallerCache
java.lang.String Class.name
java.lang.ref.SoftReference Class.reflectionData
sun.reflect.generics.repository.ClassRepository Class.genericInfo
java.lang.Object[] Class.enumConstants
java.util.Map Class.enumConstantDirectory
java.lang.Class.AnnotationData Class.annotationData
sun.reflect.annotation.AnnotationType Class.annotationType
java.lang.ClassValue.ClassValueMap Class.classValueMap
int Class.classRedefinedCount
对象 字节数 对齐填充字节 实际内存大小 备注
Integer.class 528 40 568

3.4 集合类

集合类较多,此处以 ArrayList为例。

1 ArrayList

ArrayList具有以下属性

int AbstractList.modCount
int size
Object[] elementData
实际内存大小 = 对象头 + modCount属性 + size属性 + elementData属性 + 填充对齐字节 = 12 + 4 + 4 + 4 + 0 = 24字节

不需要填充对齐字节,因此浅堆大小 = 24字节。

以下面代码为例计算深堆大小,ArrayList初始容量为10。

ArrayList<Integer> list = new ArrayList<>();
# Integer对象大小16字节
elementData数组实际内存大小 = 对象头 + 数组元素 + 填充对齐字节 = 16 + 16 * 10 + 0 = 176字节

因此,不指定容量的ArrayList对象,在初始化后深堆大小为24 + 176 = 200字节。

2 HashMap

HashMap具有以下属性

java.util.Set AbstractMap.keySet
java.util.Collection AbstractMap.values
int size
int modCount
int threshold
float loadFactor
java.util.HashMap.Node[] table
java.util.Set entrySet
实际内存大小 = 对象头 + 属性 + 填充对齐字节 = 12 + 8 * 4 + 4 = 48字节

需要填充对齐字节,浅堆大小48字节。

由于HashMap涉及的对象成员较多,此处就不计算HashMap对象深堆大小。

「如果这篇文章对你有用,请支持一下哦」

Attack On Programmer

如果这篇文章对你有用,请支持一下哦

使用微信扫描二维码完成支付