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序列化协议对不同类型的编码规则不同:
- 单个
Byte对象序列化时,需要写入完整的类元数据:包括序列化流魔数、类全限定名、序列化版本UID、字段描述信息、层级关系、校验位等固定开销,这些内容占了74字节,真正存储byte数值的部分仅1字节,总大小75字节。 byte[]作为原始类型数组,JDK序列化做了专门的紧凑编码优化:数组类型的元数据本身比普通包装类短,且元素连续按原始字节写入,不需要为每个元素重复附加元数据。长度为1的数组仅需要写入流标识、数组类型标记、数组长度、1字节实际值、结束标记,总大小仅28字节。- 取
byte[0]单独序列化时体积回到75字节,是因为writeObject()方法接收Object类型参数,传入的原始类型byte会触发自动装箱,被包装成Byte对象后再走普通对象的序列化流程,自然带上了完整的包装类元数据开销,这个过程不是“重新生成值”,只是原始类型到包装类的自动转换。
优化建议
不要为了压缩序列化体积把所有类字段都改成数组形式:
- 这种优化的收益极低,还会严重破坏代码可读性和可维护性。只有序列化连续大量同类型原始值的时候,数组的紧凑编码优势才会体现;单个字段改成单元素数组,省下来的元数据体积会被数组本身的长度、类型标识开销抵消,甚至可能出现体积反向增大的情况。
- 原始类型字段的综合优势远大于这点序列化体积差:原始类型没有对象头开销,访问不需要拆箱,CPU缓存命中率更高,日常运算、字段访问的性能远高于包装类和单元素数组。
- 如果需要做重度序列化优化,Java原生序列化本身就是性能差、体积冗余度高的选项,换用专门的二进制序列化协议或者手动按需编码字节,能拿到数倍的体积缩减和性能提升,收益远高于修改字段为数组的方案。
内容的提问来源于stack exchange,提问作者Giancarlo Metitieri
相关产品推荐
相关产品推荐

