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

如何获取表示Java对象的序列化字节数?,java,Java,例如,我将使用什么语法来获取表示字符串的字节数,并将它们与表示保存该字符串的ArrayList的字节数进行比较 我正在使用多代理系统通过消息发送对象,我希望跟踪每条消息占用的空间。该方法不必非常精确,只要它与对象的实际大小成比例缩放。例如,长度为4的字符串向量将报告为小于长度为5的字符串向量 看看: 想到的最贴切的事情是序列化它并读取字节数您可以使用和将对象转换为字节数组: 我刚刚测试过这个。您试图计算的对象的大小需要实现(这意味着您可能需要将每个对象都标记为这样才能获得其大小。这可能不可取)。

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

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

看看:


想到的最贴切的事情是序列化它并读取字节数

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

我刚刚测试过这个。您试图计算的对象的大小需要实现(这意味着您可能需要将每个对象都标记为这样才能获得其大小。这可能不可取)。我编写了一个快速而肮脏的程序来测试这一点:

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的回答强调了此方法的一些注意事项。

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


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

我认为您别无选择,只能修改代码,以便在运行时测量消息大小

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

  • 你永远不能确定这些对象是典型的
  • 各种聚合效应意味着很难从消息组件对象的序列化大小推断消息的大小。(例如,类签名每次序列化只编码一次。)
  • 这种方法不会告诉您不同消息类型的相对频率
如果您能够管理这一点,那么如果您能够度量实际消息,您将获得更准确的结果。这很可能需要修改代理框架,以对消息进行计数、度量和(理想情况下)分类。框架可能已经有了实现这一点的钩子

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

(我想你的意思是小于……)


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

在调查超过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;
    }
}

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

//创建序列化对象。
最终列表src=new ArrayList();
src.添加(“awsome”);
src.添加(“堆栈”);
src.添加(“溢出”);
System.out.println(
序列化后的大小:“+SerializationUtils.serialize((Serializable)src.length);
输出:

序列化后的大小:86
非常感谢。这正是我想要的方法。为层次结构中的所有类实现Serializable不是问题。感谢您的警告。如果我在序列化过程中遇到意外/不直观的结果,我会记住这些。如果因为太贵而无法序列化:从您自己的链接引用:“这不起作用的原因是序列化布局只是内存中真实布局的远程反映。”
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;
    }
}