如何获取表示Java对象的序列化字节数?

时间:2010-10-14 22:31:28

标签: java

我将使用什么语法来获取表示字符串的字节数,并将它们与表示保存该字符串的ArrayList的字节数进行比较,例如?

我正在使用多代理代理系统通过消息发送对象,我想跟踪每条消息占用多少空间。只要该方法与对象的实际大小成比例地缩放,该方法就不必是准确的。例如。长度为4的字符串向量将报告为小于长度为5的字符串向量。

6 个答案:

答案 0 :(得分:23)

您可以使用ObjectOutputStreamByteArrayOutputStream将对象转换为字节数组:

public static int sizeof(Object obj) throws IOException {

    ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);

    objectOutputStream.writeObject(obj);
    objectOutputStream.flush();
    objectOutputStream.close();

    return byteOutputStream.toByteArray().length;
}

我刚测试了这个。你想要计算的大小的对象需要实现Serializable(这意味着你可能必须将每个对象标记为仅仅为了获得它的大小。可能不可取)。我写了一个快速而又脏的程序来测试它:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Sizeof {

    public static class Person implements Serializable {
        private String name;
        private String age;

        public Person(String name, String age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getAge() {
            return age;
        }

        public void setAge(String age) {
            this.age = age;
        }
    }

    public static void main(String[] args) {
        Person p1 = new Person("Alby", "20");
        Person p2 = new Person("VeryLongName", "100");
        String s1 = "This is it";
        String s2 = "This";

        try {
            System.out.println("p1 " + sizeof(p1));
            System.out.println("p2 " + sizeof(p2));
            System.out.println("s1 " + sizeof(s1));
            System.out.println("s2 " + sizeof(s2));                                 
        }

        catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static int sizeof(Object obj) throws IOException {

        ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);

        objectOutputStream.writeObject(obj);
        objectOutputStream.flush();
        objectOutputStream.close();

        return byteOutputStream.toByteArray().length;
    }
}

哪位给了我:

p1 85
p2 94
s1 17
s2 11

修改

Stephen C的回答强调了这种方法的一些注意事项。

答案 1 :(得分:2)

在调查超出memcache大小的服务器错误时,我需要准确地检查每个memcache。为了避免大对象的大字节数组的开销,我将OutputStream扩展为计数器:

public class CheckSerializedSize extends OutputStream {

    /** Serialize obj and count the bytes */
    public static long getSerializedSize(Serializable obj) {
        try {
            CheckSerializedSize counter = new CheckSerializedSize();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(counter);
            objectOutputStream.writeObject(obj);
            objectOutputStream.close();
            return counter.getNBytes();
        } catch (Exception e) {
            // Serialization failed
            return -1;
        }
    }

    private long nBytes = 0;

    private CheckSerializedSize() {}

    @Override
    public void write(int b) throws IOException {
        ++nBytes;
    }

    @Override
    public void write(byte[] b, int off, int len) throws IOException {
        nBytes += len;
    }

    public long getNBytes() {
        return nBytes;
    }
}

答案 2 :(得分:1)

您可以将每个对象序列化为数组并比较每个数组的长度。在一般情况下,这不是非常准确,但通常给出了很好的近似值。

查看ObjectOutputStream(可用于序列化对象并将其转换为Bytes)和ByteArrayOutputStream(可用于保存序列化字节)。

答案 3 :(得分:1)

我认为你没有太多选择,只能修改你的代码,以便它在运行时测量消息大小。

您可以序列化示例对象并捕获和测量序列化大小。这有以下问题:

  • 您永远无法确定这些对象是否典型。
  • 各种聚合效果意味着很难从组件对象的序列化大小中推断出消息的大小。 (例如,每个序列化只对类签名编码一次。)
  • 此方法不会告诉您有关不同消息类型的相对频率的信息。

如果您可以管理此项,那么如果您可以衡量实际消息,您将获得更准确的结果。这很可能需要修改代理框架来计算,测量和(理想地)将消息分类为不同的。该框架可能已经有了这样做的钩子。

  

该方法不必是准确的,只要它与对象的实际大小成比例地缩放即可。例如。长度为4的字符串向量将报告大于长度为5的字符串向量。

(我认为你的意思是小于 ......)

您的示例说明了尝试估计序列化对象大小的问题之一。大小为4的Vector<String>的序列化可能更小......或更大......大小为Vector<String>。这取决于字符串值是什么。此外,如果消息包含两个Vector<String>个对象,则向量占用的序列化大小将小于单独序列化时两个向量的大小总和。

答案 4 :(得分:0)

查看:http://www.javaworld.com/javaworld/javaqa/2003-12/02-qa-1226-sizeof.html

想到最接近的事情就是序列化并读取字节数

答案 5 :(得分:0)

您可以使用Apache Commons如下检查序列化过程后对象的大小:

    // Create serialize objects.
    final List<String> src = new ArrayList<String>();
    src.add("awsome");
    src.add("stack");
    src.add("overflow");

    System.out.println(
            "Size after serialization:" + SerializationUtils.serialize((Serializable) src).length);

输出:

Size after serialization:86