应用程序不断接收名为Report
并将对象放入Disruptor
对于三个不同的消费者。
在 Eclipse Memory Analysis 的帮助下,每个进程的 Retained Heap SizeReport
对象平均为 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()));
}
After compress(toBytes(Report))
,物体尺寸更小:
压缩前
压缩后
现在对象的 String 大小约为 6KB。现在好多了。
这是我的问题:
还有其他数据格式的大小小于 String 吗?
每次调用序列化和压缩都会创建类似的对象ByteArrayOutputStream
, ObjectOutputStream
等等。我不想创建很多像这样的对象ByteArrayOutputStream
, ObjectOutputStream
因为我需要迭代100,000次。如何设计代码以便对象像ByteArrayOutputStream
, ObjectOutputStream
只创建一次并在每次迭代中使用它?
消费者需要对字符串进行反序列化和解压缩Disruptor
。如果我有三个消费者,那么我需要反序列化和解压缩三次。有办法吗?
Update:
正如 @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();
}