【问题标题】:Java creating new objects performanceJava 创建新对象的性能
【发布时间】:2013-10-05 16:10:03
【问题描述】:

我有以下课程。

class MyObject implements Serializable {
    private String key;
    private String val;
    private int num;

    MyObject(String a, String b, int c) {
        this.key = a;
        this.val = b;
        this.num = c;
    }
}

我需要创建一个对象列表,重复调用以下方法(比如10K次或更多)

public void addToIndex(String a, String b, int c) {
    MyObject ob = new MyObject(a,b,c);
    list.add(ob); // List<MyObject>
}

我使用分析器查看内存占用量,由于每次都创建对象,它增加了很多。有没有更好的方法来做到这一点?我正在将列表写入磁盘。

编辑:这就是我在列表完全填充后编写的方式。一旦内存超过一个值(列表的大小),有没有办法追加。

ObjectOutputStream oos = new ObjectOutputStream(
                        new DeflaterOutputStream(new FileOutputStream(
                                list)));
                oos.writeObject(list);
                oos.close();

【问题讨论】:

  • 如果你从一开始就知道你需要多少个对象,那么使用数组会更快。
  • 您是否需要始终保留列表中的所有元素?如果没有,那么您可以将一些数据以 file/db 的形式移动到磁盘
  • 不,我不会知道的。
  • @Naren 对于许多这么大的实例,您将需要一个缓存机制以使程序具有性能......您的意图对我来说很不清楚,您是否有替代方案低性能解决方案?
  • 什么是“这么多”?字符串的长度是多少?如今,10000 个对象不算什么。假设每个对象 10 KB(这已经是很长的字符串),那么 10,000 个对象只需要 100 MB。你有 OutOfMemoryErrors 吗?如果不是,那你为什么在乎?也就是说,如果目标是写入磁盘,为什么不直接写入磁盘而不是将所有内容存储在内存中?

标签: java performance list object file-io


【解决方案1】:

我使用分析器查看内存占用量,由于每次都创建对象,它增加了很多。有更好的方法吗?

Java 序列化在您的情况下不会使用那么多内存。这样做会产生大量垃圾,远远超出您的想象。它还有一个非常详细的输出,可以像你一样使用压缩来改进。

改善这种情况的一个简单方法是使用 Externalizable 而不是 Serializable。这可以显着减少产生的垃圾并使其更紧凑。它还可以更快地降低开销。

顺便说一句,如果您对列表本身使用自定义序列化,您可以获得更好的性能。

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        List<MyObject> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            list.add(new MyObject("key-" + i, "value-" + i, i));
        }

        for (int i = 0; i < 10; i++) {
            timeJavaSerialization(list);
            timeCustomSerialization(list);
            timeCustomSerialization2(list);
        }
    }

    private static void timeJavaSerialization(List<MyObject> list) throws IOException, ClassNotFoundException {
        File file = File.createTempFile("java-serialization", "dz");
        long start = System.nanoTime();
        ObjectOutputStream oos = new ObjectOutputStream(
                new DeflaterOutputStream(new FileOutputStream(file)));
        oos.writeObject(list);
        oos.close();
        ObjectInputStream ois = new ObjectInputStream(
                new InflaterInputStream(new FileInputStream(file)));
        Object o = ois.readObject();
        ois.close();
        long time = System.nanoTime() - start;
        long size = file.length();
        System.out.printf("Java serialization uses %,d bytes and too %.3f seconds.%n",
                size, time / 1e9);
    }

    private static void timeCustomSerialization(List<MyObject> list) throws IOException {
        File file = File.createTempFile("custom-serialization", "dz");
        long start = System.nanoTime();
        MyObject.writeList(file, list);
        Object o = MyObject.readList(file);
        long time = System.nanoTime() - start;
        long size = file.length();
        System.out.printf("Faster Custom serialization uses %,d bytes and too %.3f seconds.%n",
                size, time / 1e9);
    }

    private static void timeCustomSerialization2(List<MyObject> list) throws IOException {
        File file = File.createTempFile("custom2-serialization", "dz");
        long start = System.nanoTime();
        {
            DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(
                    new DeflaterOutputStream(new FileOutputStream(file))));
            dos.writeInt(list.size());
            for (MyObject mo : list) {
                dos.writeUTF(mo.key);
            }
            for (MyObject mo : list) {
                dos.writeUTF(mo.val);
            }
            for (MyObject mo : list) {
                dos.writeInt(mo.num);
            }
            dos.close();
        }
        {
            DataInputStream dis = new DataInputStream(new BufferedInputStream(
                    new InflaterInputStream(new FileInputStream(file))));
            int len = dis.readInt();
            String[] keys = new String[len];
            String[] vals = new String[len];
            List<MyObject> list2 = new ArrayList<>(len);
            for (int i = 0; i < len; i++) {
                keys[i] = dis.readUTF();
            }
            for (int i = 0; i < len; i++) {
                vals[i] = dis.readUTF();
            }
            for (int i = 0; i < len; i++) {
                list2.add(new MyObject(keys[i], vals[i], dis.readInt()));
            }
            dis.close();
        }
        long time = System.nanoTime() - start;
        long size = file.length();
        System.out.printf("Compact Custom serialization uses %,d bytes and too %.3f seconds.%n",
                size, time / 1e9);
    }


    static class MyObject implements Serializable {
        private String key;
        private String val;
        private int num;

        MyObject(String a, String b, int c) {
            this.key = a;
            this.val = b;
            this.num = c;
        }

        MyObject(DataInput in) throws IOException {
            key = in.readUTF();
            val = in.readUTF();
            num = in.readInt();
        }

        public void writeTo(DataOutput out) throws IOException {
            out.writeUTF(key);
            out.writeUTF(val);
            out.writeInt(num);
        }

        public static void writeList(File file, List<MyObject> list) throws IOException {
            DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(
                    new DeflaterOutputStream(new FileOutputStream(file))));
            dos.writeInt(list.size());
            for (MyObject mo : list) {
                mo.writeTo(dos);
            }
            dos.close();
        }

        public static List<MyObject> readList(File file) throws IOException {
            DataInputStream dis = new DataInputStream(new BufferedInputStream(
                    new InflaterInputStream(new FileInputStream(file))));
            int len = dis.readInt();
            List<MyObject> list = new ArrayList<>(len);
            for (int i = 0; i < len; i++) {
                list.add(new MyObject(dis));
            }
            dis.close();
            return list;
        }
    }
}

终于打印出来了

Java serialization uses 61,168 bytes and too 0.061 seconds.
Faster Custom serialization uses 62,519 bytes and too 0.024 seconds.
Compact Custom serialization uses 68,225 bytes and too 0.020 seconds.

如您所见,我尝试使文件更紧凑,而不是使其更快,这是您应该测试性能改进的一个很好的例子。

【讨论】:

【解决方案2】:

考虑使用快速序列化。它在源代码级别与 JDK 序列化兼容,并减少了臃肿。 此外,它击败了大多数手工制作的“可外部化”序列化,因为它不仅是 JDK 序列化实现本身,而且是库存 JDK 的低效输入/输出流实现,这会损害性能。

http://code.google.com/p/fast-serialization/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-01
    • 2018-03-18
    • 2018-05-25
    • 1970-01-01
    • 2015-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多