4

Nettyを使用して大きなファイルのアップロードを実行しています。正常に動作しますが、クライアントが使用する RAM はファイルのサイズとともに増加するようです。すべてがソース ファイルの読み取りからターゲット ファイルの書き込みにパイプされるため、これは予期された動作ではありません。

最初は、Xmx に達するまで成長する一種のアダプティブ バッファーを考えましたが、 Xmx を適切な値 (50M) に設定すると、アップロードを開始した直後にOutOfMemoryError が発生します。Eclipse Memory Analyzer を使用していくつかの調査を行った結果、ヒープ メモリを保持するオブジェクトは次のようになります。

org.jboss.netty.channel.socket.nio.NioSocketChannel$WriteRequestQueue

このキューに制限を設定するオプションはありますか、または ChannelFutures を使用して独自のキューをコーディングして、バイト数を制御し、制限に達したときにパイプをブロックする必要がありますか?

ご協力いただきありがとうございます、

よろしく、

ルノー

4

2 に答える 2

2

Netty Github の @normanmaurer からの回答

使用する必要があります

Channel.isWritable()

「キュー」がいっぱいかどうかを確認します。その場合は、さらに書き込むのに十分なスペースがあるかどうかを確認する必要があります。したがって、データをすばやく書き込んでクライアントに送信すると、目に見える効果が発生する可能性があります。DefaultFileRegion または ChunkedFile を介してファイルを書き込もうとすると、この種の問題を回避できます。


@normanmaurerありがとうございます、チャンネルのこの方法を見逃しました!内部で何が起こっているかを読む必要があると思います:

org.jboss.netty.handler.stream.ChunkedWriteHandler

更新: 2012/08/30 これは、私の問題を解決するために作成したコードです。

public class LimitedChannelSpeaker{
    Channel channel;
    final Object lock = new Object();
    long maxMemorySizeB;
    long size = 0;
    Map<ChannelBufferRef, Integer> buffer2readablebytes = new HashMap<ChannelBufferRef, Integer>();

    public LimitedChannelSpeaker(Channel channel, long maxMemorySizeB) {
        this.channel= channel;
        this.maxMemorySizeB = maxMemorySizeB;
    }

    public ChannelFuture speak(ChannelBuffer buff) {
        if (buff.readableBytes() > maxMemorySizeB) {
            throw new IndexOutOfBoundsException("The buffer is larger than the maximum allowed size of " + maxMemorySizeB + "B.");
        }
        synchronized (lock) {
            while (size + buff.readableBytes() > maxMemorySizeB) {
                try {
                    lock.wait();
                } catch (InterruptedException ex) {
                    throw new RuntimeException(ex);
                }
            }
            ChannelBufferRef ref = new ChannelBufferRef(buff);
            ref.register();
            ChannelFuture future = channel.write(buff);
            future.addListener(new ChannelBufferRef(buff));
            return future;
        }
    }

    private void spoken(ChannelBufferRef ref) {
        synchronized (lock) {
            ref.unregister();
            lock.notifyAll();
        }
    }

    private class ChannelBufferRef implements ChannelFutureListener {

        int readableBytes;

        public ChannelBufferRef(ChannelBuffer buff) {
            readableBytes = buff.readableBytes();
        }

        public void unregister() {
            buffer2readablebytes.remove(this);
            size -= readableBytes;
        }

        public void register() {
            buffer2readablebytes.put(this, readableBytes);
            size += readableBytes;
        }

        @Override
        public void operationComplete(ChannelFuture future) throws Exception {
            spoken(this);
        }
    }
}
于 2012-08-29T13:11:59.957 に答える
0

デスクトップ バックグラウンド アプリケーション用

Netty は、たとえば約 10,000 接続の拡張性の高いサーバー向けに設計されています。接続数が数百未満のデスクトップ アプリケーションの場合は、プレーン IO を使用します。コードははるかに単純で、1 MB 未満しか使用しないはずです。

于 2012-08-29T09:08:07.950 に答える