2012-03-20 10 views
1

独自のメッセージングシステムでSpringリモート処理(Java直列化を使用)を介して通信するクライアントとサーバーがあります。私のサーバーは大きなオブジェクトを返すので、私のSpring Remotingの実装は直列化されたオブジェクトのバイト配列をブロックに分割し、複数のメッセージを送信します。クライアントは与えられた要求に対するすべての応答メッセージを待って、最終的に以下のメソッドを呼び出してバイト配列をデシリアライズして結果のオブジェクトにします。1つの大きな配列に入れないでバイト配列ブロックを逆シリアル化する方法

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

これは完全に機能します。しかし、その非常に重い記憶。ブロック

  1. List<byte[]>含む
  2. :非常に大まかメモリ内のシリアライズされたバイト配列と同じサイズをメモリ内のオブジェクトをされたと仮定すると、私はメモリ内の私のオブジェクトの3倍の大きさのようなもので終わりますByteArrayOutputStreamには連結バイト配列が含まれています(ByteArrayOutputStream.toByteArray()は配列をコピーするため別の配列も可能です)。

このメソッドは、すべてのアレイがGC'dすることができ返しますが、このメソッドの呼び出し時のメモリ使用量に大きなスパイクがあります一度

  • たオブジェクト。

    私の質問には:私はそれらを受け取るように私はバイト配列を追加することができますブロッキングバイト入力ストリームを作成する方法はありますか? ObjectOutputStreamは(別のスレッドで)利用可能なバイトを読み込み、さらにバイトが書き込まれるまでブロックし、オブジェクトが完全に非直列化されるまで続行します。このように、私はメモリ内に完全に連結されたバイト配列を持つ必要はありません。標準的なストリームの実装はどれも適合していないようですが、NIOをどのように使用するのか分かりませんし、そこに1つあれば独自のストリーム実装を書くのではないでしょう。あなたはまた、効率化のためにもread(byte[],int,int)をオーバーライドする必要がありますが、これはゆっくりと少しあれば動作します勿論

    多くのおかげで、 イアン

  • 答えて

    2

    は、オーバーヘッド

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

    配列を軽減するために、独自の入力ストリームを実装します

    PipedInputStreamPipedOutputStreamのコンボは、本当に必要なものに使用できます。入力ストリームは何かが読み取られるまでブロックされます

    +1

    +1これは匿名の内部クラスとして行うべきではありません。 :) – biziclop

    +0

    私はちょうど一緒に静的な入れ子になった、または完全なクラスでも良いと打ちました –

    +0

    私はそれがOPのためのアドバイスの言葉だったと思って、やや不器用な言葉。 – biziclop

    0

    完全性のために、以下のように、サーバーからのブロックをサーバーに逆シリアル化するクライアントの新しい(テスト)実装は、Pipeストリームを@rachetfreak提案する。ありがとう!

    public static class Client implements Runnable { 
        private final PipedInputStream deserializationInputStream = new PipedInputStream(BLOCK_SIZE); 
        private final PipedOutputStream deserializationOutputStream; 
    
        public Client() throws IOException { 
         deserializationOutputStream = new PipedOutputStream(deserializationInputStream); 
        } 
    
        /** Called by messaging system when a message is received */ 
        public void onReceive(byte[] block) throws Exception { 
         deserializationOutputStream.write(block); 
        } 
    
        public Object readObject() throws Exception { 
         ObjectInputStream objectInputStream = new ObjectInputStream(deserializationInputStream); 
         Object readObject = objectInputStream.readObject(); 
         objectInputStream.close(); 
         return readObject; 
        } 
    
        @Override 
        public void run() { 
         try { 
          Object readObject = readObject(); 
          System.out.println("read: " + readObject); 
         } catch (Exception e) { 
          e.printStackTrace(); 
         } 
        } 
    } 
    
    関連する問題