繁体   English   中英

NioSocketChannel $ WriteRequestQueue导致内存不足

[英]NioSocketChannel$WriteRequestQueue causing OutOfMemory

我正在使用Netty执行大文件上传 它工作正常,但客户端使用的RAM似乎随着文件的大小而增加。 这不是预期的行为,因为从读取源文件到写入目标文件都通过管道传输。

最初,我想到了一种自适应缓冲区,直到到达Xmx为止,但是将Xmx设置为合理的值(50M)会在开始上传后立即导致OutOfMemoryError 经过使用Eclipse Memory Analyzer的研究,看来保留堆内存的对象是:

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

是否有任何设置此队列限制的选项,或者我必须使用ChannelFutures对自己的队列进行编码,以控制字节数并在达到限制时阻塞管道?

谢谢你的帮助,

问候,

雷诺

@normanmaurer在Netty Github上的回答

你应该用

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

用于桌面后台应用程序

Netty用于高度可扩展的服务器,例如大约10,000个连接。 对于连接少于几百个的桌面应用程序,我将使用普通IO。 您可能会发现代码简单得多,并且应使用少于1 MB的内存。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM