簡體   English   中英

為什么Java序列化會占用這么多空間?

[英]Why does Java serialization take up so much space?

我嘗試序列化Byte和Integer實例,並為另一端接收到它們占用了多少空間而感到震驚。 為什么制作一個整數只需要4個字節,而序列化卻要占用那么多字節的10倍? 我的意思是在C ++中,最終類具有一個64位的類標識符及其內容。 按照這種邏輯,我希望一個整數在序列化時占用64 + 32或96位。

import java.io.*;

public class Test {
    public static void main (String[] ar) throws Exception {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutput out = new ObjectOutputStream(bos);   
        out.writeObject(new Integer(32));
        byte[] yourBytes = bos.toByteArray();
        System.out.println("length: " + yourBytes.length + " bytes");
    }
}

輸出:

長度:81個字節

更新:

public static void main(String[] args) throws IOException {

    {
    ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
    ObjectOutput out1 = new ObjectOutputStream(bos1);
    out1.writeObject(new Boolean(false));
    byte[] yourBytes = bos1.toByteArray();
    System.out.println("1 Boolean length: " + yourBytes.length);
    }

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutput out = new ObjectOutputStream(bos);
    for (int i = 0; i < 1000; ++i) {
        out.writeObject(new Boolean(true)); // 47 bytes
    }
    byte[] yourBytes = bos.toByteArray();
    System.out.println("1000 Booleans length: " + yourBytes.length); // 7040 bytes

    final int count = 1000;

    ArrayList<Boolean> listBoolean = new ArrayList<>(count);
    listBoolean.addAll(Collections.nCopies(count, Boolean.TRUE));
    System.out.printf("ArrayList: %d%n", sizeOf(listBoolean)); // 5096 bytes

    Boolean[] arrayBoolean = new Boolean[count];
    Arrays.fill(arrayBoolean, true);
    System.out.printf("Boolean[]: %d%n", sizeOf(arrayBoolean)); // 5083 bytes

    boolean[] array = new boolean[count];
    Arrays.fill(array, true);
    System.out.printf("boolean[]: %d%n", sizeOf(array)); // 1027 bytes

    BitSet bits = new BitSet(count);
    bits.set(0, count);
    System.out.printf("BitSet: %d%n", sizeOf(bits)); // 201 bytes
}

static int sizeOf(Serializable obj) throws IOException {
    ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
    ObjectOutputStream objsOut = new ObjectOutputStream(bytesOut);
    objsOut.writeObject(obj);
    return bytesOut.toByteArray().length;
}

輸出:

1個布爾長度:47(每個布爾47字節)

1000個布爾值長度:7040(每個布爾值7個字節)

ArrayList:5096(每個布爾值5個字節)

Boolean []:5083(每個布爾值5個字節)

boolean []:1027(每個布爾值1個字節)

位集:201(每個布爾值1字節的1/5)

盡管Radiodef闡明了為什么序列化對象的大小很大,但是我想在這里再說一點,這樣我們就不會忘記底層Java序列化算法(幾乎所有算法)中存在的優化。

當您寫入另一個Integer對象(或任何已寫入的對象)時,在這種情況下,您不會看到相似的大小(我的意思是大小不會是81 * 2 = 162字節),

ObjectOutput out = new ObjectOutputStream(bos);   
out.writeObject(new Integer(32));
out.writeObject(new Integer(65));
byte[] yourBytes = bos.toByteArray();
System.out.println("length: " + yourBytes.length + " bytes");

它的工作方式是,當首次請求類的實例(對象)進行序列化時,它將寫入有關整個類的信息 即包括類名,它會寫出類中存在的每個字段的名稱 這就是為什么字節數更多的原因。 這基本上是為了正確處理班級評估案例。

當它第一次發送該類的元數據時,它還將相同的信息緩存到稱為值緩存或間接表的本地緩存中。 因此,下一次當請求同一類的另一個實例進行序列化時(請記住,高速緩存僅適用於流級別,或者在調用reset()之前適用),它將僅寫入一個標記(僅4個字節的信息),因此大小會更少。

java.lang.Bytejava.lang.Integer是對象,因此至少還需要存儲其類的合格名稱,以便對其進行反序列化。 另外,還需要存儲serialVersionUID ,等等。我們可以輕松地看到這些額外的信息如何快速增大大小。

如果您想了解序列化格式,請在JavaWorld上找到有關它的文章: http : //www.javaworld.com/article/2072752/the-java-serialization-algorithm-revealed.html


如果您擔心序列化數據的大小,請選擇一種更緊湊的格式:

import java.util.*;
import java.io.*;

class Example {
    public static void main(String[] args) throws IOException {
        final int count = 1000;

        ArrayList<Boolean> list = new ArrayList<>(count);
        list.addAll(Collections.nCopies(count, Boolean.TRUE));
        System.out.printf("ArrayList: %d%n", sizeOf(list));

        boolean[] array = new boolean[count];
        Arrays.fill(array, true);
        System.out.printf("boolean[]: %d%n", sizeOf(array));

        BitSet bits = new BitSet(count);
        bits.set(0, count);
        System.out.printf("BitSet: %d%n", sizeOf(bits));
    }

    static int sizeOf(Serializable obj) throws IOException {
        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
        ObjectOutputStream objsOut = new ObjectOutputStream(bytesOut);
        objsOut.writeObject(obj);
        return bytesOut.toByteArray().length;
    }
}
ArrayList: 5096
boolean[]: 1027
BitSet: 201

Ideone的示例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM