我们正在将Java 8 Spring Boot 2用于我们的微服务应用程序。在本地运行负载测试会注意到堆正在消耗内存,但从不释放内存。我正在使用G1垃圾收集器运行该应用程序,并且还通过JVisualVM进行了手动GC,但是仍然无法释放分配的内存。
我进行了堆转储并进行了分析,我可以清楚地看到由System Class Loader创建的大字节数组被列为泄漏可疑对象。我看到字节数组实例将我的HTTP请求保存到端点“/test”。但是负载测试已经完成,线程又回到了运行负载测试之前的状态。
不知道为什么系统类加载器加载的字节数组包含所有这些元素,并且无缘无故地占用了所有这些堆。
JVisualVM
Leak Suspects
byte Array
Objects with Outgoing Ref
/test端点是@RestController类中的唯一方法
@RequestMapping(value = "/test", method = RequestMethod.GET)
@CrossOrigin(origins = "*")
public void test() {
logger.info("Testing1...");
}
以下是与服务器相关的Spring Boot application.properties:
server.port=8090
server.tomcat.max-threads=200
server.tomcat.accept-count=100
server.tomcat.min-spare-threads=20
server.error.whitelabel.enabled=false
server.max-http-header-size=2097152
最佳答案
Tomcat缓存了许多对象以使其运行更快。使用server.max-http-header-size=2097152
设置,您使那些缓存的对象之一声明了2 MB的内存并保留了该内存。在这种情况下,它是Http11OutputBuffer
,您可以看到here声明(在您的情况下)2 MB的内存。 Http11OutputBuffer
由Http11Processor
使用,您可以看到here。
documentation关于processorCache
有以下说法:
The protocol handler caches Processor objects to speed up performance. This setting dictates how many of these objects get cached. -1 means unlimited, default is 200. If not using Servlet 3.0 asynchronous processing, a good default is to use the same as the maxThreads setting. If using Servlet 3.0 asynchronous processing, a good default is to use the larger of maxThreads and the maximum number of expected concurrent requests (synchronous and asynchronous).
所以我的建议是将
server.max-http-header-size
设置为更合理的值,例如8KB(默认值),并在测试表明您确实需要它时慢慢加倍(related:当总 header 大小大于server.max-http-header-size
时,Tomcat抛出“400 Bad Request”)。
关于Java堆内存持有大字节数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58420606/