我正在使用 Netty 执行大型文件上传。它工作正常,但客户端使用的RAM似乎随着文件的大小而增加。这不是预期的行为,因为所有内容都是从读取源文件到写入目标文件。
起初,我想到了一种自适应缓冲区,直到达到Xmx,但将Xmx设置为合理值(50M)会在开始上传后立即导致OutOfMemoryError 。 在使用Eclipse Memory Analyzer进行一些研究之后,似乎保留堆内存的对象是:
org.jboss.netty.channel.socket.nio.NioSocketChannel$WriteRequestQueue
是否有任何设置此队列限制的选项,还是我必须使用ChannelFutures编码自己的队列来控制字节数并在达到限制时阻塞管道?
感谢您的帮助,
此致
雷诺
答案 0 :(得分:2)
来自@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);
}
}
}
答案 1 :(得分:0)
用于桌面后台应用程序
Netty专为高度可扩展的服务器而设计,例如大约10,000个连接。对于少于几百个连接的桌面应用程序,我会使用普通IO。您可能会发现代码更简单,并且应该使用不到1 MB。