应用程序不断接收名为Report
的对象,并将对象放入Disruptor
以供三个不同的消费者使用。
在Eclipse Memory Analysis的帮助下,每个Report
对象的保留堆大小平均为20KB。应用程序以-Xmx2048
开头,表示应用程序的堆大小为2GB。
但是,对象的数量一次大约为100,000,这意味着所有对象的总大小约为2GB。
要求是所有100,000个对象都应加载到Disruptor
中,以便消费者异步使用数据。但是,如果每个对象的大小都大到20KB,那就不可能了。
所以我想将对象序列化为String
并压缩它:
private static byte[] toBytes(Serializable o) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
return baos.toByteArray();
}
private static String compress(byte[] str) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(out);
gzip.write(str);
gzip.close();
return new String(Base64Coder.encode(out.toByteArray()));
}
在compress(toBytes(Report))
之后,对象大小更小:
压缩之前
压缩后
现在,对象的字符串大约是6KB。现在好多了。
这是我的问题:
是否有其他数据格式的大小小于String?
每次调用序列化和压缩都会创建ByteArrayOutputStream
,ObjectOutputStream
等对象。我不想创建许多对象,例如ByteArrayOutputStream
,ObjectOutputStream
,因为我需要迭代100,000次。如何设计代码以便像ByteArrayOutputStream
,ObjectOutputStream
这样的对象只创建一次并在每次迭代中使用它?
消费者需要从Disruptor
反序列化和解压缩字符串。如果我有三个消费者,那么我需要反序列化和解压缩三次。任何方式?
更新
正如@BoristheSpider建议的那样,序列化和压缩应该在一个动作中执行:
private static byte[] compressObj(Serializable o) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
GZIPOutputStream zos = new GZIPOutputStream(bos);
ObjectOutputStream ous = new ObjectOutputStream(zos);
ous.writeObject(o);
zos.finish();
bos.flush();
return bos.toByteArray();
}
答案 0 :(得分:0)
使用ObjectOutputStream和压缩比使用Disruptor要昂贵得多,它会破坏使用它的目的。它可能要贵1000倍。
最好不要限制一次排队的对象数量。除非您的设计存在严重错误,否则只有1000个20 KB对象的队列应该足以确保所有消费者都能高效工作。
顺便说一句,如果你需要持久性,我会使用Chronicle(部分是因为我写了它)这不需要压缩或byte []或字符串存储,持久存储所有消息,你的队列是无限的,完全脱离堆。即你的100K对象将使用<< 1 MB的堆。