首页 > 解决方案 > 内存泄漏问题 org.apache.tomcat.util.collections.SynchronizedStack 类

问题描述

我们对我们的 Spring Boot 文件下载应用程序进行了负载测试,加载了 4000 个并发用户,其中 3995 个成功,其中 5 个失败。

我们下载的文件是1 MB每个请求的。

我们在负载测试结束时使用了堆转储

jcmd pid GC.heap_dump <filename>

分析堆转储后,我意识到tomcat的 org.apache.tomcat.util.collections.SynchronizedStack<org.apache.tomcat.util.net.NioChannel> 没有被释放。我们已经对 500、700 和 4000 的多个用户负载进行了测试。这个特定的对象在内存中不断增加,但没有释放任何东西。

这是我在 application.properties 中的 tomcat 配置

server.tomcat.connection-timeout=20s
server.tomcat.accept-count=5000
server.tomcat.max-connections=50000
server.tomcat.max-threads=10000
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

我是否在我的 tomcat 配置中缺少任何用于 Spring Boot 的内容?

应用程序堆栈:Open JDK 11 上的 spring boot 2.2.0.RELEASE。

我们用于文件下载的一些代码:

@GetMapping(path = "/file/download/{downloadToken}")
@ApiOperation(value = "downloadFile", authorizations = {@Authorization(value = "apiKey")})
public StreamingResponseBody downloadFile(@PathVariable String downloadToken,
    HttpServletResponse response) {
    MyFileObject myFileObject = myFileService.downloadFile(downloadToken);
    response.setContentType(myFileObject.getContentType());
    response.setHeader("Content-Disposition",
        "attachment; filename=\"" + myFileObject.getFileName() + "\"");
    return out -> {
        try (OutputStream os = out) {
            os.write(myFileObject.getData());
        }
    };
}

作为 DTO 的 MyFileObject

@Getter
@Setter
@AllArgsConstructor
@ToString
class MyFileObject {
    private String fileName;
    private String contentType;
    private byte[] data;
}

注意:由于其他业务原因,我们在内存中有整个 byte[] 数据(1 MB)。但是,根据堆转储,这不是泄漏的原因,因为这些对象是 GCed。

来自堆转储的 MAT 工具的一些屏幕截图

堆摘要 在此处输入图像描述

标签: javaspringspring-boottomcat

解决方案


推荐阅读