monkeyWie / proxyee

HTTP proxy server,support HTTPS&websocket.MITM impl,intercept and tamper HTTPS traffic.
MIT License
1.52k stars 572 forks source link

堆外内存不够 #188

Open shaoneng111 opened 2 years ago

shaoneng111 commented 2 years ago

项目运行一段时间后,直接内存就会逐步占满,报错。 message: failed to allocate 16777216 byte(s) of direct memory (used: 1811939335, max: 1823473664)。 不知道该如何定位问题,这是属于堆外内存溢出了?还请大佬指导下

monkeyWie commented 2 years ago

看起来是有内存没回收,你是自定义了拦截器吗

shaoneng111 commented 2 years ago

是的,自定义了,像下面这样会有问题么?

public class UserAgentIntercept extends HttpProxyIntercept {

@Override
public void beforeRequest(Channel clientChannel, HttpRequest httpRequest, HttpProxyInterceptPipeline pipeline) throws Exception {
    // 转到下一个拦截器处理
    pipeline.beforeRequest(clientChannel, httpRequest);
}
shaoneng111 commented 2 years ago

我看大佬写的测试用例里,对于自定义的拦截器,也没有做特殊的回收呢?

shaoneng111 commented 2 years ago

自定义了三四个拦截器,向下面这样return前close会出现内存不回收的情况吗?

public void beforeRequest(Channel clientChannel, HttpRequest httpRequest, HttpProxyInterceptPipeline pipeline) throws Exception { HttpHeaders httpHeaders = httpRequest.headers(); String url = httpHeaders.get("Host") + HttpUtils.getPath(httpRequest.uri()); if (forbidService.checkUrlBlackMatch(url)) { FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, urlBlackList); fullHttpResponse.content().writeBytes(HitUrlBlacklist.reasonPhrase().getBytes()); clientChannel.writeAndFlush(fullHttpResponse); clientChannel.close(); return; } }

monkeyWie commented 2 years ago

这个fullHttpResponse可能需要手动回收下,你可以试试看

shaoneng111 commented 2 years ago

自定义了三四个拦截器,向下面这样return前close会出现内存不回收的情况吗?

public void beforeRequest(Channel clientChannel, HttpRequest httpRequest, HttpProxyInterceptPipeline pipeline) throws Exception { HttpHeaders httpHeaders = httpRequest.headers(); String url = httpHeaders.get("Host") + HttpUtils.getPath(httpRequest.uri()); if (forbidService.checkUrlBlackMatch(url)) { FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, urlBlackList); fullHttpResponse.content().writeBytes(HitUrlBlacklist.reasonPhrase().getBytes()); clientChannel.writeAndFlush(fullHttpResponse); clientChannel.close(); return; } }


我在这个方法clientChannel.close()之后加了 ReferenceCountUtil.release(fullHttpResponse),还是会有堆外内存逐步变多的情况,可能还是用法不对。 我自己是实现HttpProxyIntercept类的:public class BlackListForbidIntercept extends HttpProxyIntercept 这里是否改成实现FullRequestIntercept或FullResponseIntercept会有效果?不知道是不是这个原因,因为现在我的服务会代理很多类型的Url,不知道是否是其他原因引起的溢出,看起来不是没写 ReferenceCountUtil.release(fullHttpResponse)的原因,大佬指导下

monkeyWie commented 2 years ago

你可以启动的时候加上这个参数-Dio.netty.leakDetection.level=advanced,在内存泄漏的时候会有详细的日志打印出来,然后贴出来我看看

shaoneng111 commented 2 years ago

加-Dio.netty.leakDetection.level=advanced这个。服务现在部署在服务器上,上传日志中心,log4j配置level为info,能写到日志中心么,还是需要到服务器上手动执行jar包观察堆栈?这个不太确定啊

shaoneng111 commented 2 years ago

httpProxyExceptionHandle捕获到的异常如下: beforeCatch异常捕获报错:

before catch, message: java.lang.NullPointerException, cause: java.lang.NullPointerException, stackTrace: io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:478)/nio.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)/nio.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)/nio.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)/nio.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)/nio.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)/nio.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)/nio.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)/nio.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)/nio.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)/nio.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)/nio.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)/nio.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)/nio.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)/nio.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)/nio.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)/nio.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)/njava.lang.Thread.run(Thread.java:745)

afterCatch异常捕获报错: after catch, message: java.lang.NullPointerException, cause: java.lang.NullPointerException, stackTrace: io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:478)/nio.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)/nio.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)/nio.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)/nio.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)/nio.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)/nio.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)/nio.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)/nio.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)/nio.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)/nio.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)/nio.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)/nio.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)/nio.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)/nio.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)/nio.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)/nio.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)/njava.lang.Thread.run(Thread.java:745)

不知道内存溢出和这两个报错有关么?

monkeyWie commented 2 years ago

看不出啥有用的信息啊,但是估计和这个有关系