Java 基础类型大小

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容