Java netty中的内存问题

Java netty中的内存问题,java,netty,Java,Netty,我正在使用Netty 4.0.32。 我已分配MaxDirectMemorySize:256M 我的引导程序如下所示: bootStrap = new ServerBootstrap(); childGroup = new NioEventLoopGroup(); bootStrap.localAddress(protocolConstant.getPort()); bootStrap.channel(NioServerSocketChannel.class); bootStrap.group(

我正在使用Netty 4.0.32。 我已分配MaxDirectMemorySize:256M

我的引导程序如下所示:

bootStrap = new ServerBootstrap();
childGroup = new NioEventLoopGroup();
bootStrap.localAddress(protocolConstant.getPort());
bootStrap.channel(NioServerSocketChannel.class);
bootStrap.group(PARENTGROUP, childGroup);
bootStrap.childHandler(new MailChannelInitializer());
bootStrap.option(ChannelOption.SO_BACKLOG, BACKLOG);
bootStrap.childOption(ChannelOption.AUTO_READ, true);
bootStrap.childOption(ChannelOption.MAX_MESSAGES_PER_READ, 1 * 1024);
bootStrap.childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 512);
bootStrap.childOption(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 256);
bootStrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
我的管道如下所示:

bootStrap = new ServerBootstrap();
childGroup = new NioEventLoopGroup();
bootStrap.localAddress(protocolConstant.getPort());
bootStrap.channel(NioServerSocketChannel.class);
bootStrap.group(PARENTGROUP, childGroup);
bootStrap.childHandler(new MailChannelInitializer());
bootStrap.option(ChannelOption.SO_BACKLOG, BACKLOG);
bootStrap.childOption(ChannelOption.AUTO_READ, true);
bootStrap.childOption(ChannelOption.MAX_MESSAGES_PER_READ, 1 * 1024);
bootStrap.childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 512);
bootStrap.childOption(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 256);
bootStrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
SslHandler ByteToMessageCodec(将ByteBuf转换为byte[],反之亦然)BusinessLogicHandler

1) SSL支持的SSL句柄。我正在使用java的SslEngine

2) 我对ByteToMessageCodec进行如下扩展:

private class ByteConversionCodec extends ByteToMessageCodec<byte[]> {

    @Override
    protected void encode(ChannelHandlerContext ctx, byte[] msg, ByteBuf out)
            throws Exception {
        if (!ctx.channel().isWritable()) {
            ctx.flush();
        }
        out.writeBytes(msg);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in,
            List<Object> out) throws Exception {
        byte[] arr;
        if (in.hasArray()) {
            arr = in.array();
        }
        else {
            arr = new byte[in.readableBytes()];
            in.readBytes(arr);
        }
        out.add(arr);
    }

}
私有类ByteConversionDec扩展ByteToMessageCodec{
@凌驾
受保护的void编码(ChannelHandlerContext ctx,字节[]msg,ByteBuf out)
抛出异常{
如果(!ctx.channel().isWritable()){
ctx.flush();
}
out.writeBytes(msg);
}
@凌驾
受保护的无效解码(ChannelHandlerContext ctx、ByteBuf in、,
列出)抛出异常{
字节[]arr;
if(在.hasArray()中){
arr=in.array();
}
否则{
arr=新字节[in.readableBytes()];
in.readBytes(arr);
}
out.add(arr);
}
}
如果调用encode时通道不可写,我会添加一个刷新请求,以便通道再次变为可写。这是正确的吗

3) BusinessLogicHandler将处理指定给一个线程池,该线程池执行异步处理(涉及IO)并使用SocketChannel对象写回管道。所有写操作都源自线程池。最后,我在所有写入之后添加一个flush(),以便刷新所有挂起的写入。每个写调用都涉及一个最大大小为300字节的字节[]。所有写入总计约为20Mb

Thread [nioEventLoopGroup-3-1] (Suspended)  
    Thread.sleep(long) line: not available [native method]  
    Bits.reserveMemory(long, int) line: 651 
    DirectByteBuffer.<init>(int) line: 123  
    ByteBuffer.allocateDirect(int) line: 306    
    PoolArena$DirectArena.newChunk(int, int, int, int) line: 645    
    PoolArena$DirectArena(PoolArena<T>).allocateNormal(PooledByteBuf<T>, int, int) line: 228    
    PoolArena$DirectArena(PoolArena<T>).allocate(PoolThreadCache, PooledByteBuf<T>, int) line: 212  
    PoolArena$DirectArena(PoolArena<T>).allocate(PoolThreadCache, int, int) line: 132   
    PooledByteBufAllocator.newDirectBuffer(int, int) line: 271  
    PooledByteBufAllocator(AbstractByteBufAllocator).directBuffer(int, int) line: 155   
    PooledByteBufAllocator(AbstractByteBufAllocator).directBuffer(int) line: 146    
    PooledByteBufAllocator(AbstractByteBufAllocator).buffer(int) line: 83   
    SslHandler.allocate(ChannelHandlerContext, int) line: 1504  
    SslHandler.allocateOutNetBuf(ChannelHandlerContext, int) line: 1514 
    SslHandler.wrap(ChannelHandlerContext, boolean) line: 517   
    SslHandler.flush(ChannelHandlerContext) line: 500   
    DefaultChannelHandlerContext(AbstractChannelHandlerContext).invokeFlush() line: 663 
    DefaultChannelHandlerContext(AbstractChannelHandlerContext).flush() line: 644   
    Server$MailChannelInitializer$ByteConversionCodec.encode(ChannelHandlerContext, byte[], ByteBuf) line: 134  
    Server$MailChannelInitializer$ByteConversionCodec.encode(ChannelHandlerContext, Object, ByteBuf) line: 1    
    ByteToMessageCodec$Encoder.encode(ChannelHandlerContext, I, ByteBuf) line: 168  
    ByteToMessageCodec$Encoder(MessageToByteEncoder<I>).write(ChannelHandlerContext, Object, ChannelPromise) line: 107  
    Server$MailChannelInitializer$ByteConversionCodec(ByteToMessageCodec<I>).write(ChannelHandlerContext, Object, ChannelPromise) line: 108 
    DefaultChannelHandlerContext(AbstractChannelHandlerContext).invokeWrite(Object, ChannelPromise) line: 633   
    AbstractChannelHandlerContext.access$1900(AbstractChannelHandlerContext, Object, ChannelPromise) line: 32   
    AbstractChannelHandlerContext$WriteTask(AbstractChannelHandlerContext$AbstractWriteTask).write(AbstractChannelHandlerContext, Object, ChannelPromise) line: 908 
    AbstractChannelHandlerContext$WriteTask(AbstractChannelHandlerContext$AbstractWriteTask).run() line: 893    
    NioEventLoop(SingleThreadEventExecutor).runAllTasks(long) line: 358 
    NioEventLoop.run() line: 357    
    SingleThreadEventExecutor$2.run() line: 112 
    DefaultThreadFactory$DefaultRunnableDecorator.run() line: 137   
    FastThreadLocalThread(Thread).run() line: 745   
线程[nioEventLoopGroup-3-1](挂起)
Thread.sleep(长)行:不可用[本机方法]
位。保留内存(长,int)行:651
DirectByteBuffer.(int)行:123
ByteBuffer.allocateDirect(int)行:306
PoolArena$DirectArena.newChunk(int,int,int,int)行:645
PoolArena$DirectArena(PoolArena).allocateNormal(PooledByteBuf,int,int)行:228
PoolArena$DirectArena(PoolArena).allocate(PoolThreadCache,PooledByteBuf,int)行:212
PoolArena$DirectArena(PoolArena).分配(PoolThreadCache,int,int)行:132
PooledByteBuffAllocator.newDirectBuffer(int,int)行:271
PooledByteBufAllocator(AbstractByteBufAllocator).directBuffer(int,int)行:155
PooledByteBufAllocator(AbstractByteBufAllocator).directBuffer(int)行:146
缓冲区(int)行:83
SslHandler.allocate(ChannelHandlerContext,int)行:1504
SslHandler.allocateOutNetBuf(ChannelHandlerContext,int)行:1514
换行(ChannelHandlerContext,布尔值)行:517
SslHandler.flush(ChannelHandlerContext)行:500
DefaultChannelHandlerContext(AbstractChannelHandlerContext).invokeFlush()行:663
DefaultChannelHandlerContext(AbstractChannelHandlerContext).flush()行:644
服务器$MailChannelInitializer$ByteConversionDec.encode(ChannelHandlerContext,字节[],字节数)行:134
服务器$MailChannelInitializer$ByteConversionDec.encode(ChannelHandlerContext,Object,ByteBuf)行:1
ByteToMessageCodec$Encoder.encode(ChannelHandlerContext,I,ByteBuf)行:168
ByteToMessageCodec$Encoder(MessageToByteEncoder).write(ChannelHandlerContext,Object,ChannelPromise)行:107
服务器$MailChannelInitializer$ByteConversionDec(ByteToMessageCodec)。写入(ChannelHandlerContext,Object,ChannelPromise)行:108
DefaultChannelHandlerContext(AbstractChannelHandlerContext).invokeWrite(对象,ChannelPromise)行:633
AbstractChannelHandlerContext.access$1900(AbstractChannelHandlerContext,Object,ChannelPromise)行:32
AbstractChannelHandlerContext$WriteTask(AbstractChannelHandlerContext$AbstractWriteTask)
AbstractChannelHandlerContext$WriteTask(AbstractChannelHandlerContext$AbstractWriteTask).run()行:893
NioEventLoop(SingleThreadEventExecutor).runAllTasks(长)行:358
NioEventLoop.run()行:357
SingleThreadEventExecutor$2.run()行:112
DefaultThreadFactory$DefaultRunnableDecorator.run()行:137
FastThreadLocalThread(Thread).run()行:745
正因为如此,我发现在获取内容方面出现了延迟。线程休眠一段时间以获取内存。有谁能帮我解决这个问题吗?多谢各位

如果调用encode时通道不可写,我会添加一个刷新请求,以便通道再次变为可写。这是正确的吗

我觉得那不合适。您的编码器没有尝试写入通道,它应该只是尝试将
字节[]
写入
ByteBuf
。您的BusinessLogicHandler已经决定是否写入以及是否刷新

您是否尝试删除此代码以查看它是否修复了您的问题

if (!ctx.channel().isWritable()) {
    ctx.flush();
}
如果调用encode时通道不可写,我会添加一个刷新请求,以便通道再次变为可写。这是正确的吗

我觉得那不合适。您的编码器没有尝试写入通道,它应该只是尝试将
字节[]
写入
ByteBuf
。您的BusinessLogicHandler已经决定是否写入以及是否刷新

您是否尝试删除此代码以查看它是否修复了您的问题

if (!ctx.channel().isWritable()) {
    ctx.flush();
}

当我缓冲整个20Mb内容并在单个writeAndFlush()调用中发送时,不会发生此问题。当我缓冲整个20Mb内容并在单个writeAndFlush()调用中发送时,不会发生此问题。