Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get amount of serialized bytes representing a Java object?

Tags:

java

What syntax would I use to get the number of bytes representing a string and compare them to the number of bytes representing an ArrayList holding that string, for example?

I am using a multi-agent agent system to send objects via messages and I want to keep track of how much space each message takes up. The method doesn't have to be dead-on accurate, as long as it scales proportionally to the actual size of the object. E.g. a Vector of strings of length 4 will report as smaller than a Vector of strings of length 5.

like image 505
Chris Redford Avatar asked Oct 14 '10 22:10

Chris Redford


People also ask

How is Java object serialized?

To serialize an object means to convert its state to a byte stream so that the byte stream can be reverted back into a copy of the object. A Java object is serializable if its class or any of its superclasses implements either the java. io. Serializable interface or its subinterface, java.

Does serialization reduce size?

In some cases, the secondary intention of data serialization is to minimize the data's size which then reduces disk space or bandwidth requirements.

How do you convert objects to bytes?

Write the contents of the object to the output stream using the writeObject() method of the ObjectOutputStream class. Flush the contents to the stream using the flush() method. Finally, convert the contents of the ByteArrayOutputStream to a byte array using the toByteArray() method.

How many methods serializable has in Java?

Serializable interface has two methods, readResolve() and writeReplace() , which are used to read and write object in database.


2 Answers

You can convert your object into a byte array using ObjectOutputStream and ByteArrayOutputStream:

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;
}

I just tested this out. The object who's size you're trying to calculate, needs to implement Serializable (which means you may have to mark every object as such simply to get its size. Might not be desirable). I wrote a quick and dirty program to test this out:

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;
    }
}

Which gave me:

p1 85
p2 94
s1 17
s2 11

EDIT

Stephen C's answer highlights some caveats with this method.

like image 86
Vivin Paliath Avatar answered Oct 12 '22 21:10

Vivin Paliath


I needed to check this accurately per-memcache write while investigating a server bug where memcache sizes were exceeded. To avoid the overhead of a big byte array for large objects I extended OutputStream as a counter:

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;
    }
}
like image 30
mwk Avatar answered Oct 12 '22 19:10

mwk