Java 基础类型:
- int
- short
- long
- byte
- boolean
- char
- float
- double
如何查看基础类型大小(需要多少个字节)
两种方法:1. 使用Instrumentation工具类;2. 使用Unsafe
1. 使用Instrumentation工具类
Instrumentation工具类一般用于一些分析工具,用来分析JVM内存等。Instrumentation 是一个接口,获取 Instrumentation 实例有两种方式:
(a) JVM 启动时将 Instrumentation 通过 premain 方法传给javaagent。
(b) JVM 提供的一种加载后启动 agent 的方式,这种情况下 Instrumentation 实例会被传给 agentmain方法。
下面用第一种方式获取 Instrumentation 实例,首先定义一个 agent 类,然后添加 premain 方法:
public class MyAgent {
private static Instrumentation inst;
public static void premain(String agentArgs, Instrumentation inst) {
MyAgent.inst = inst;
}
public static Instrumentation getInst() {
return MyAgent.inst;
}
}
然后将 agent 打包,需要定义 MANIFEST.MF 文件中的 Premain-Class
Manifest-Version: 1.0
Premain-Class: com.leo.study.javafeatures.base.types.MyAgent
若使用 maven 打包,可以在 maven-jar-plugin 中加入配置来指定 MF 文件的路径:
<configuration>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
打完包将 jar 包引入到项目中,添加 VM 参数:("c:/lib/" 为我这边放的父目录,根据需要调整)
-javaagent:C:/lib/myagent-0.0.1-SNAPSHOT.jar
添加测试代码获取对象大小
import java.lang.instrument.Instrumentation;
public class TypesAndSize {
public static void main(String[] args) {
TypesAndSize typesAndSize = new TypesAndSize();
Instrumentation inst = MyAgent.getInst();
System.out.println("Size of typesAndSize: " + inst.getObjectSize(typesAndSize));
for (int i = 1; i <= 10; i ++) {
System.out.println("Size of byte arr of length is "+ i + " : " + inst.getObjectSize(new byte[i]));
}
System.out.println("---------------");
for (int i = 1; i <= 10; i ++) {
System.out.println("Size of short arr of length is "+ i + " : " + inst.getObjectSize(new short[i]));
}
System.out.println("---------------");
for (int i = 1; i <= 10; i ++) {
System.out.println("Size of int arr of length is "+ i + " : " + inst.getObjectSize(new int[i]));
}
System.out.println("---------------");
for (int i = 1; i <= 10; i ++) {
System.out.println("Size of Integer arr of length is "+ i + " : " + inst.getObjectSize(new Integer[i]));
}
System.out.println("---------------");
for (int i = 1; i <= 10; i ++) {
System.out.println("Size of long arr of length is "+ i + " : " + inst.getObjectSize(new long[i]));
}
}
}
输出如下,根据输出做一些简单分析可以得到,byte 占用1个字节,short - 2个字节,int-4个字节,long-8个字节;
还可以看出前16个字节用于存放其他信息;以及不够8字节的对齐;
Size of typesAndSize: 16
Size of byte arr of length is 1 : 24
Size of byte arr of length is 2 : 24
Size of byte arr of length is 3 : 24
Size of byte arr of length is 4 : 24
Size of byte arr of length is 5 : 24
Size of byte arr of length is 6 : 24
Size of byte arr of length is 7 : 24
Size of byte arr of length is 8 : 24
Size of byte arr of length is 9 : 32
Size of byte arr of length is 10 : 32
---------------
Size of short arr of length is 1 : 24
Size of short arr of length is 2 : 24
Size of short arr of length is 3 : 24
Size of short arr of length is 4 : 24
Size of short arr of length is 5 : 32
Size of short arr of length is 6 : 32
Size of short arr of length is 7 : 32
Size of short arr of length is 8 : 32
Size of short arr of length is 9 : 40
Size of short arr of length is 10 : 40
---------------
Size of int arr of length is 1 : 24
Size of int arr of length is 2 : 24
Size of int arr of length is 3 : 32
Size of int arr of length is 4 : 32
Size of int arr of length is 5 : 40
Size of int arr of length is 6 : 40
Size of int arr of length is 7 : 48
Size of int arr of length is 8 : 48
Size of int arr of length is 9 : 56
Size of int arr of length is 10 : 56
---------------
Size of Integer arr of length is 1 : 24
Size of Integer arr of length is 2 : 24
Size of Integer arr of length is 3 : 32
Size of Integer arr of length is 4 : 32
Size of Integer arr of length is 5 : 40
Size of Integer arr of length is 6 : 40
Size of Integer arr of length is 7 : 48
Size of Integer arr of length is 8 : 48
Size of Integer arr of length is 9 : 56
Size of Integer arr of length is 10 : 56
---------------
Size of long arr of length is 1 : 24
Size of long arr of length is 2 : 32
Size of long arr of length is 3 : 40
Size of long arr of length is 4 : 48
Size of long arr of length is 5 : 56
Size of long arr of length is 6 : 64
Size of long arr of length is 7 : 72
Size of long arr of length is 8 : 80
Size of long arr of length is 9 : 88
Size of long arr of length is 10 : 96
2. 使用 Unsafe 的 objectFieldOffset 方法获取基础类型大小
首先定义基础变量
private boolean boolean1 = false;
private boolean boolean2 = false;
private byte byte1 = 1;
private short short1 = '1';
private char char1 = 'c';
private int int1 = 60;
private long long1 = 345L;
private float float1 = 3.14f;
private double double1 = 3.1415d;
private String string1 = "aString";
private String string2 = "theEnd";
利用反射获取 Unsafe 实例,遍历对象的 fields, 获取offset, 根据offset计算大小
public void getSizeByUnsafe() {
try {
Class unSafeClass = this.getClass().getClassLoader().loadClass("sun.misc.Unsafe");
Field unsafeField = unSafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe theUnsafe = (Unsafe) unsafeField.get(null);
HashMap<Long, String> offsetMap = new HashMap<Long, String>(16);
List<Long> offsetList = new ArrayList<>();
for (Field f : TypesAndSize.class.getDeclaredFields()) {
Long offset = theUnsafe.objectFieldOffset(f);
offsetMap.put(offset, f.getName());
offsetList.add(offset);
}
Collections.sort(offsetList);
offsetList.forEach(l -> {
String name = offsetMap.get(l);
out.println("TypesAndSize field " + name + " offset is : " + l);
});
} catch (Exception e) {
e.printStackTrace();
}
}
输出如下:(默认开启压缩指针的情况)
TypesAndSize field int1 offset is : 12
TypesAndSize field long1 offset is : 16
TypesAndSize field double1 offset is : 24
TypesAndSize field float1 offset is : 32
TypesAndSize field short1 offset is : 36
TypesAndSize field char1 offset is : 38
TypesAndSize field boolean1 offset is : 40
TypesAndSize field boolean2 offset is : 41
TypesAndSize field byte1 offset is : 42
TypesAndSize field string1 offset is : 44
TypesAndSize field string2 offset is : 48
| 类型 | 大小(Byte) |
|---|---|
| int | 4 |
| long | 8 |
| double | 8 |
| float | 4 |
| short | 2 |
| char | 2 |
| boolean | 1 |
| byte | 1 -- 这里offset差为2,很奇怪,后续要看一下 |
| 引用对象 | 4 -- 默认开启压缩指针的情况 |
对象在堆中的结构(64位机器):
非数组对象: MarkWord (8 byte) + (4/8 byte)class 对象指针 + 数据区 + 对齐8byte
数据对象: MarkWord (8 byte) + (4/8 byte)class 对象指针 + 数组长度(4 byte) + 数据区 + 对齐8byte
markword 数据结构:
http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/oops/markOop.hpp
synchronized 的锁机制:
https://wiki.openjdk.java.net/display/HotSpot/Synchronization