我有一个高容量的网络服务器,不断消耗内存。使用jmap,我已经跟踪了管道似乎不断增长和增长的事实(以及nio套接字等)。就像套接字不会断开连接一样。
我对ServerBootstrap的初始化是:
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(coreThreads, workThreads, Runtime.getRuntime().availableProcessors()*2));
bootstrap.setOption("child.keepAlive", false);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setPipelineFactory(new HttpChannelPipelineFactory(this, HttpServer.IdleTimer));
bootstrap.bind(new InetSocketAddress(host, port));
coreThreads和workThreads是java.util.concurrent.Executors.newCachedThreadPool()。
IdleTimer是私有静态Timer IdleTimer = new HashedWheelTimer();
我的管道工厂是:
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("idletimer", new HttpIdleHandler(timer));
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("chunkwriter", new ChunkedWriteHandler());
pipeline.addLast("http.handler" , handler);
pipeline.addLast("http.closer", new HttpClose());
HttpIdleHandler是示例中给出的基本库存空闲处理程序,除了使用“all”。它不会经常被执行。超时为500毫秒。 (又名1/2秒)。空闲处理程序在通道上调用close。 HttpClose()是一个简单的关闭通道的所有东西,只是处理程序不处理它。它的执行非常不规律。
一旦我在处理程序中发送了响应(从SimpleChannelUpstreamHandler派生),无论keepalive设置如何,我都会关闭通道。我已经通过向close()返回的ChannelFuture通道添加一个监听器来验证我正在关闭通道,并且侦听器中的isSuccess值为true。
jmap输出中的一些示例(列是排名,实例数,大小(以字节为单位),类名称):
3: 147168 7064064 java.util.HashMap$Entry
4: 90609 6523848 org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext
6: 19788 3554584 [Ljava.util.HashMap$Entry;
8: 49893 3193152 org.jboss.netty.handler.codec.http.HttpHeaders$Entry
11: 11326 2355808 org.jboss.netty.channel.socket.nio.NioAcceptedSocketChannel
24: 11326 996688 org.jboss.netty.handler.codec.http.HttpRequestDecoder
26: 22668 906720 org.jboss.netty.util.internal.LinkedTransferQueue
28: 5165 826400 [Lorg.jboss.netty.handler.codec.http.HttpHeaders$Entry;
30: 11327 815544 org.jboss.netty.channel.AbstractChannel$ChannelCloseFuture
31: 11326 815472 org.jboss.netty.channel.socket.nio.DefaultNioSocketChannelConfig
33: 12107 774848 java.util.HashMap
34: 11351 726464 org.jboss.netty.util.HashedWheelTimer$HashedWheelTimeout
36: 11327 634312 org.jboss.netty.channel.DefaultChannelPipeline
38: 11326 634256 org.jboss.netty.handler.timeout.IdleStateHandler$State
45: 10417 500016 org.jboss.netty.util.internal.LinkedTransferQueue$Node
46: 9661 463728 org.jboss.netty.util.internal.ConcurrentIdentityHashMap$HashEntry
47: 11326 453040 org.jboss.netty.handler.stream.ChunkedWriteHandler
48: 11326 453040 org.jboss.netty.channel.socket.nio.NioSocketChannel$WriteRequestQueue
51: 11326 362432 org.jboss.netty.handler.codec.http.HttpChunkAggregator
52: 11326 362432 org.jboss.netty.util.internal.ThreadLocalBoolean
53: 11293 361376 org.jboss.netty.handler.timeout.IdleStateHandler$AllIdleTimeoutTask
57: 4150 323600 [Lorg.jboss.netty.util.internal.ConcurrentIdentityHashMap$HashEntry;
58: 4976 318464 org.jboss.netty.handler.codec.http.DefaultHttpRequest
64: 11327 271848 org.jboss.netty.channel.SucceededChannelFuture
65: 11326 271824 org.jboss.netty.handler.codec.http.HttpResponseEncoder
67: 11326 271824 org.jboss.netty.channel.socket.nio.NioSocketChannel$WriteTask
73: 5370 214800 org.jboss.netty.channel.UpstreamMessageEvent
74: 5000 200000 org.jboss.netty.channel.AdaptiveReceiveBufferSizePredictor
81: 5165 165280 org.jboss.netty.handler.codec.http.HttpHeaders
84: 1562 149952 org.jboss.netty.handler.codec.http.DefaultCookie
96: 2048 98304 org.jboss.netty.util.internal.ConcurrentIdentityHashMap$Segment
98: 2293 91720 org.jboss.netty.buffer.BigEndianHeapChannelBuffer
我错过了什么?什么线程负责释放它对管道(或套接字?通道?)的引用,以便垃圾收集器收集这个内存?似乎有一些大的哈希表持有它们(我从上面的列表中筛选出几个对哈希表条目的引用)。
答案 0 :(得分:2)
除非您在应用程序中引用Channel
,ChannelPipeline
,ChannelHandlerContext
,否则一旦连接关闭,它们就会无法访问。请仔细检查您的应用程序是否在某处提及其中一个应用程序。有时匿名类是一个很好的嫌疑人,但使用堆转储文件无法得到准确的答案。