java - 如何反序列化字节数组 block 而不放入一个大数组

标签 java serialization stream

我有一个客户端和服务器通过专有消息系统上的 Spring 远程处理(使用 Java 序列化)进行通信。我的服务器返回大对象,因此我的 Spring 远程处理实现将序列化对象字节数组拆分为 block ,并发送多条消息。客户端等待给定请求的所有响应消息,并最终调用下面的方法将字节数组反序列化为结果对象。

protected Object deserialize(List<byte[]> blocks) {
    try {
        ByteArrayOutputStream os = new ByteArrayOutputStream(blocks.size() * blockSize);
        for (byte[] b : blocks) {
            os.write(b, 0, b.length);
        }
        ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
        ObjectInputStream objInputStream = new ObjectInputStream(is);
        return objInputStream.readObject();
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

这非常有效。然而,它的内存力很重。假设内存中的对象与其在内存中的序列化字节数组的大小大致相同,我最终得到的大小大约是内存中对象大小的 3 倍:

  1. List<byte[]>包含 block
  2. ByteArrayOutputStream包含连接的字节数组(可能还有另一个,因为 ByteArrayOutputStream.toByteArray() 复制数组)。
  3. 生成的对象

一旦此方法返回,所有数组都可以被 GC 回收,但在此方法调用期间,内存使用量会出现大幅上升。

所以,对于我的问题:有没有一种方法可以创建一个阻塞字节输入流,我可以在收到字节数组时将其附加到其中? ObjectOutputStream 将(在单独的线程中)读取可用字节,然后阻塞直到写入更多字节,并继续直到对象完全反序列化。这样,我就不必在内存中保存完整的串联字节数组。标准流实现似乎都不适合,我看不出如何使用 NIO 来做到这一点,而且如果有足够的流实现,我宁愿不编写自己的流实现。

非常感谢, 伊恩

最佳答案

实现您自己的输入流以减少数组开销

protected Object deserialize(final List<byte[]> blocks) {
    try {
       ObjectInputStream objInputStream = new ObjectInputStream(InputStream(){
            Iterator<byte[]> it=blocks.iterator();
            byte[] curr;
            int ind;
            public int read(){
                if(curr==null||curr.length==ind){
                    if(!it.hasNext())return -1;//or use a blocking queue and pop
                    curr=it.next();
                    ind=0;
                }
                return curr[ind++];
            }
        });
        return objInputStream.readObject();
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

当然,为了提高效率,您还应该重写read(byte[],int,int),但如果速度有点慢,这会起作用

或者您可以使用 PipedInputStreamPipedOutputStream组合你真正想要的。输入流将阻塞,直到有东西要读取

关于java - 如何反序列化字节数组 block 而不放入一个大数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9796412/

相关文章:

java - 什么是短路,在 Java 编程中如何使用?

c# - 使用重复元素反序列化 XML

node.js - createReadStream 的 TypeScript 定义不接受选项中的 {start : 90, end: 99 }

c# - 将字节数组保存到文件

javascript - RxJS:识别组合流中的流源的正确模式?

java - pymemcached 缓存中的下一个唯一键

java - B 类构造函数的参数 0 需要 A 类类型的 bean,但无法找到

java - 在 Stream 中使用 null 值

java - 使用 Java 的 Apache Spark 对象序列化

android - Parcelable遇到IOException写入可序列化对象引起java.io.NotSerializableException : retrofit2. Retrofit$1