You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java序列化时长度为1的byte数组为何比单个Byte对象体积小?

Java序列化场景下单元素byte数组比Byte对象体积更小的问题解答

问题复现

近期在Java中做内存相关实验,将对象序列化为二进制数据时观测到反常现象:长度为1的byte数组,序列化后的二进制体积比单个Byte对象更小,测试结果如下:

  • 单个Byte对象序列化结果:体积75字节
101011001110110100000000000001010111001101110010000000000000111001101010011000010111011001100001001011100110110001100001011011100110011100101110010000100111100101110100011001011001110001001110011000001000010011101110010100001111010100011100000000100000000000000001010000100000000000000101011101100110000101101100011101010110010101111000011100100000000000010000011010100110000101110110011000010010111001101100011000010110111001100111001011100100111001110101011011010110001001100101011100101000011010101100100101010001110100001011100101001110000010001011000000100000000000000000011110000111000000000001
  • 长度为1的byte[1]数组序列化结果:体积28字节
10101100111011010000000000000101011101010111001000000000000000100101101101000010101011001111001100010111111110000000011000001000010101001110000000000010000000000000000001111000011100000000000000000000000000000000000100000001
  • 读取数组中byte[0]元素单独序列化:体积回到75字节
101011001110110100000000000001010111001101110010000000000000111001101010011000010111011001100001001011100110110001100001011011100110011100101110010000100111100101110100011001011001110001001110011000001000010011101110010100001111010100011100000000100000000000000001010000100000000000000101011101100110000101101100011101010110010101111000011100100000000000010000011010100110000101110110011000010010111001101100011000010110111001100111001011100100111001110101011011010110001001100101011100101000011010101100100101010001110100001011100101001110000010001011000000100000000000000000011110000111000000000001

测试使用的统计代码如下:

public class MemoryFunctions {
    static int sizeOf(Object input) {
        int size = 0;
        ByteArrayOutputStream checker = new ByteArrayOutputStream();

        try {
            ObjectOutputStream byteArray = new ObjectOutputStream(checker);
            byteArray.writeObject(input);
            byteArray.flush();
            byte sizeDetector[]  = checker.toByteArray();
            size = sizeDetector.length;
            int amountOfBytes = 0;
            for (byte b:
                 sizeDetector) {
                System.out.print(String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0'));
                amountOfBytes +=1;
            }
            System.out.println("real size in byte " + amountOfBytes);
            System.out.println();
        } catch (Exception e) {
            System.err.println(e);
        }
        return size;
    }
}

核心原因解释

先理清几个容易混淆的基础概念:

  • 你测量的是Java原生序列化框架输出的字节流体积,不是JVM堆内存中对象的实际占用大小,二者没有直接对应关系。
  • byte是原始基本类型,Byte是对应的引用类型包装类,byte[]是存储原始byte值的数组对象——认为二者都是原始类型、直接原样存储在内存里的判断是错误的。

体积差异的本质是JDK序列化协议对不同类型的编码规则不同:

  1. 单个Byte对象序列化时,需要写入完整的类元数据:包括序列化流魔数、类全限定名、序列化版本UID、字段描述信息、层级关系、校验位等固定开销,这些内容占了74字节,真正存储byte数值的部分仅1字节,总大小75字节。
  2. byte[]作为原始类型数组,JDK序列化做了专门的紧凑编码优化:数组类型的元数据本身比普通包装类短,且元素连续按原始字节写入,不需要为每个元素重复附加元数据。长度为1的数组仅需要写入流标识、数组类型标记、数组长度、1字节实际值、结束标记,总大小仅28字节。
  3. 取byte[0]单独序列化时体积回到75字节,是因为writeObject()方法接收Object类型参数,传入的原始类型byte会触发自动装箱,被包装成Byte对象后再走普通对象的序列化流程,自然带上了完整的包装类元数据开销,这个过程不是“重新生成值”,只是原始类型到包装类的自动转换。

优化建议

不要为了压缩序列化体积把所有类字段都改成数组形式:

  • 这种优化的收益极低,还会严重破坏代码可读性和可维护性。只有序列化连续大量同类型原始值的时候,数组的紧凑编码优势才会体现;单个字段改成单元素数组,省下来的元数据体积会被数组本身的长度、类型标识开销抵消,甚至可能出现体积反向增大的情况。
  • 原始类型字段的综合优势远大于这点序列化体积差:原始类型没有对象头开销,访问不需要拆箱,CPU缓存命中率更高,日常运算、字段访问的性能远高于包装类和单元素数组。
  • 如果需要做重度序列化优化,Java原生序列化本身就是性能差、体积冗余度高的选项,换用专门的二进制序列化协议或者手动按需编码字节,能拿到数倍的体积缩减和性能提升,收益远高于修改字段为数组的方案。

内容的提问来源于stack exchange,提问作者Giancarlo Metitieri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 01:27:17