目录
一、文章内容介绍
本篇文章介绍Java8 实际占用内存分析,其引用了很多网上文章+个人实践理解,希望可以让读者快速了解实际Java占用内存。
二、实验环境
1、OS:mac os 10.12.6
2、IDE:IntelliJ IDEA 2018.1.4 (Ultimate Edition)
Build #IU-181.5087.20, built on May 17, 2018
Licensed to Rover12421 / Rover12421
You have a perpetual fallback license for this version
Subscription is active until December 31, 2099
JRE: 1.8.0_152-release-1136-b39 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
macOS 10.12.6
3、Java:Java8,64位模式
Java HotSpot(TM) 64-Bit Server VM (build 25.112-b16, mixed mode)
4、Memory Analyzer tool:Eclipse Memory Analyzer Version 1.9.2 官网
5、对象头分析jar:
<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
三、Java基本类型占用字节数
Java基本类型 | 字节数 |
Byte | 1 |
Boolean | 1 |
Character | 2 |
Short | 2 |
Integer | 4 |
Float | 4 |
Long | 8 |
Double | 8 |
四、Java对象内存组成
Java对象内存组成分成(java一个对象占用多少字节?一个Java对象到底占用多大内存?):
对象头+实例数据+对齐填充。
* 本文章主要描述MAT工具分析对象内存,故默认为对象头指针压缩。
* 上述实例数据包括原生类型、引用类型自身,但是不包含引用类型实际指向的内存占用(比如Object[],其数组长度不同所占内存不同,这里不计入)。
其中对齐填充是指对象所占内存必须为8字节的倍数,如果不够则进行填充(占用额外内存)。故不同类型实践如下:
类型 | 对象头 | 实例数据 | 对齐填充 | 总字节数 |
Byte | 12 | 1 | 3 | 16 |
Boolean | 12 | 1 | 3 | 16 |
Character | 12 | 2 | 2 | 16 |
Short | 12 | 2 | 2 | 16 |
Integer | 12 | 4 | 0 | 16 |
Float | 12 | 4 | 0 | 16 |
Long | 12 | 8 | 4 | 24 |
Double | 12 | 8 | 4 | 24 |
String | 12 | 8(value:4+hash:4字段) | 4 | 24 |
Object | 12 | 0 | 4 | 16 |
Integer[] | 16 | 0 | 0 | 16 |
Object[] | 16 | 0 | 0 | 16 |
ArrayList | 12 | 12(modCount:4+size:4+elementData:4) | 0 | 24 |
ArrayList[] | 16 | 0 | 0 | 16 |
可以看到几个规则(开启压缩模式):
- 数组类型,对象本身(不计算子项实例)固定占用16字节;
- 引用类型,对象本身固定4个字节;
- 原生类型,对象本身占用内存需加上自身占用内存;
- 最终不足8倍数的,要进行对齐填充。
然后对象本身的内存计算和对象实际内存计算有时不同,比如引用类型,比如数组。
另外同样是String类型,计算单个String对象所占内存时需要计算其内部的value和hash字段,共计24个字节;但如果是作为被应用的对象(比如某个类字段),则只需4个字节;下面通过实验验证。
五、Java对象内存实践
直接上代码,具体pom应用见【一、实验环境】第5条。
package javalearn;
import org.openjdk.jol.info.ClassLayout;
import java.util.ArrayList;
import java.util.List;
class C1 extends Object {
private int size;
}
class C2 extends Object {
private String str;
}
class C3 extends Object {
private Object[] objs = new Object[10];
}
class C4 extends Object {
private boolean bl;
}
class C5 extends Object {
private int idInt;
private long idLong;
private double idDouble;
private String name;
public List<Long> array;
}
public class Howmanybytes {
public static void main(String[] args) {
System.out.println("----------------------------------------------");
System.out.print(ClassLayout.parseClass(Byte.class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Boolean.class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Character.class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Short.class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Integer.class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Float.class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Long.class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Double.class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(String.class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Object.class).toPrintable());
System.out.println();
System.out.println("----------------------------------------------");
System.out.print(ClassLayout.parseClass(Byte[].class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Boolean[].class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Character[].class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Short[].class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Integer[].class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Float[].class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Long[].class).toPrintable());
System.out.println();
System.out.print(ClassLayout.parseClass(Double[].class).toPrintable());
System.out.println();
System.out.print(ClassLayout