java.lang.OutOfMemoryError 使用 Spring Boot WebFlux Starter

Posted

技术标签:

【中文标题】java.lang.OutOfMemoryError 使用 Spring Boot WebFlux Starter【英文标题】:java.lang.OutOfMemoryError on using Spring Boot WebFlux Starter 【发布时间】:2018-09-27 21:41:37 【问题描述】:

我已经使用 Spring Boot(版本 1.5.1 RELEASE)、Spring Cloud(Edgware.SR3)、Spring Cloud Starter Config(版本 1.4.3 RELEASE)和 Netflix 的 Eureka 命名服务器(Spring Cloud Starter Netflix Eureka Client)创建了 2 个微服务/服务器 1.4.4 发布):

    Eureka 服务器(用于注册微服务的服务) Eureka 客户端(用于保存/更新操作的数据库服务)

Eureka Client 是一个简单的 Restful 服务,带有一个带注解的@PostMapping 方法,该方法接受 sizeable object 作为参数 (@RequestBody MyObject object)。

Eureka 客户端成功注册到 Eureka 服务器。

然后在 Spring Boot Webflux 的帮助下,我尝试在 WebClient 类的帮助下访问我的 Eureka 客户端,该类在 Spring 5 中引入,是 AsyncRestTemplate 类的即兴创作。我做了如下的事情:

WebClient webClient = WebClient.create();
reactor.core.publisher.Mono result = (Mono) webClient.post()
.uri("http://localhost:8080/eureka-client")
.body(BodyInserters.fromObject(//myComplexObject here))
.retrieve()
.bodyToMono(String.class);

result.subscribe();

在调试时,我发现在上述代码的最后一行之后出现 OOM 异常。

io.netty.handler.codec.EncoderException: java.lang.OutOfMemoryError

下面的完整堆栈跟踪:

[reactor-http-nio-4] WARN  io.netty.util.concurrent.AbstractEventExecutor  - A task raised an exception. Task: reactor.ipc.netty.channel.ContextHandler$$Lambda$401/11401686@10ae5a2

reactor.core.Exceptions$ErrorCallbackNotImplemented: io.netty.handler.codec.EncoderException: java.lang.OutOfMemoryError

Caused by: io.netty.handler.codec.EncoderException: java.lang.OutOfMemoryError

                at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:106)

                at io.netty.channel.CombinedChannelDuplexHandler.write(CombinedChannelDuplexHandler.java:348)

                at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:738)

                at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:730)

                at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:816)

                at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:723)

                at reactor.ipc.netty.channel.ChannelOperationsHandler.doWrite(ChannelOperationsHandler.java:291)

                at reactor.ipc.netty.channel.ChannelOperationsHandler.drain(ChannelOperationsHandler.java:465)

                at reactor.ipc.netty.channel.ChannelOperationsHandler.flush(ChannelOperationsHandler.java:191)

                at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776)

                at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:802)

                at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:814)

                at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:794)

                at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:831)

                at io.netty.channel.DefaultChannelPipeline.writeAndFlush(DefaultChannelPipeline.java:1051)

                at io.netty.channel.AbstractChannel.writeAndFlush(AbstractChannel.java:300)

                at reactor.ipc.netty.http.HttpOperations.lambda$then$0(HttpOperations.java:135)

                at reactor.ipc.netty.FutureMono.lambda$deferFuture$0(FutureMono.java:68)

                at reactor.ipc.netty.FutureMono$DeferredFutureMono.subscribe(FutureMono.java:134)

                at reactor.core.publisher.Mono.subscribe(Mono.java:3008)

                at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:167)

                at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56)

                at reactor.core.publisher.Mono.subscribe(Mono.java:3008)

                at reactor.core.publisher.FluxConcatIterable$ConcatIterableSubscriber.onComplete(FluxConcatIterable.java:141)

                at reactor.core.publisher.FluxConcatIterable.subscribe(FluxConcatIterable.java:60)

                at reactor.core.publisher.MonoSourceFlux.subscribe(MonoSourceFlux.java:47)

                at reactor.ipc.netty.channel.ChannelOperations.applyHandler(ChannelOperations.java:380)

                at reactor.ipc.netty.http.client.HttpClientOperations.onHandlerStart(HttpClientOperations.java:501)

                at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)

                at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)

                at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:463)

                at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886)

                at java.lang.Thread.run(Thread.java:745)

Caused by: java.lang.OutOfMemoryError

                at sun.misc.Unsafe.allocateMemory(Native Method)

                at io.netty.util.internal.PlatformDependent0.allocateDirectNoCleaner(PlatformDependent0.java:430)

                at io.netty.util.internal.PlatformDependent.allocateDirectNoCleaner(PlatformDependent.java:596)

                at io.netty.buffer.PoolArena$DirectArena.allocateDirect(PoolArena.java:764)

                at io.netty.buffer.PoolArena$DirectArena.newChunk(PoolArena.java:740)

                at io.netty.buffer.PoolArena.allocateNormal(PoolArena.java:244)

                at io.netty.buffer.PoolArena.allocate(PoolArena.java:214)

                at io.netty.buffer.PoolArena.allocate(PoolArena.java:146)

                at io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:324)

                at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:185)

                at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:176)

                at io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:113)

                at io.netty.handler.codec.http.HttpObjectEncoder.encode(HttpObjectEncoder.java:92)

                at io.netty.handler.codec.http.HttpClientCodec$Encoder.encode(HttpClientCodec.java:167)

                at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:88)

                ... 32 more

我的类路径中有 jackson 库,并依靠 spring 序列化我的复杂对象,同时将它传递给 Restful 服务。我不确定是什么原因造成的。请问有什么指点吗?

【问题讨论】:

您的“复杂对象”的序列化可能出现问题。您能否将其添加到问题中? @SrThompson 它的业务代码,所以我不能真正分享它,但它是一个包含许多对象组合(列表、地图等)的巨大对象。所以也许你这么说是对的。它可能是由于大的对象大小造成的。但是,我已经为 netty 类启用了日志记录,所以让我看看是否可以获得一些证明这一点的日志。 检查 netty 参数,如发送和接收缓冲区,以及 jvm 选项 -XX:MaxDirectMemorySize=...,并确保您有足够的可用内存。 【参考方案1】:

在java执行路径中添加这个

-Dio.netty.noPreferDirect=true

【讨论】:

以上是关于java.lang.OutOfMemoryError 使用 Spring Boot WebFlux Starter的主要内容,如果未能解决你的问题,请参考以下文章