我们正在运行grpc-java
0.8.0版服务器来处理远程调用。服务器逻辑非常简单,只需从数据库中获取给定id指定的数据并将其设置为redis
缓存。
JVM参数配置为-Xss256k -Xmx8G
。服务器启动后,JVM占用了4GB内存(在top
中为RES),并处理了大约400 QPS。我发出了jmap命令jmap -histo:live <pid>
并获得了以下转储文件:
num #instances #bytes class name
----------------------------------------------
1: 4998400 119961600 io.netty.buffer.PoolThreadCache$MemoryRegionCache$Entry
2: 212415 23503536 [B
3: 11076 20170816 [Lio.netty.buffer.PoolThreadCache$MemoryRegionCache$Entry;
4: 70853 10010904 [C
5: 28819 2518640 [Lio.netty.util.Recycler$DefaultHandle;
6: 31232 1998848 com.mysql.jdbc.ConnectionPropertiesImpl$BooleanConnectionProperty
7: 7287 1764136 [I
8: 70000 1680000 java.lang.String
9: 45766 1464512 java.util.Hashtable$Entry
10: 134 1291992 [D
11: 14376 1265088 io.netty.buffer.PooledUnsafeDirectByteBuf
12: 5527 1160200 [Ljava.util.HashMap$Node;
13: 16340 1116584 [[B
从中我们可以看到有大量的
io.netty.buffer.PoolThreadCache$MemoryRegionCache$Entry
实例占用了大约100MB的内存。 (请注意grpc
使用netty
作为其通信层。)这似乎是异常的。即使那样,堆中对象也无法占用多达4GB的内存。这必须归因于堆外内存的使用,例如netty
使用的直接缓冲区。堆内存泄漏了吗?
为什么会发生这种情况?以及如何解决或诊断这个问题?
最佳答案
升级到grpc-java 0.9.0或更高版本(引入了Netty 4.1 Beta6或更高版本)可以解决此问题。目前尚不清楚是由于在与分配线程不同的线程上释放缓冲区而导致的问题是错误还是效率低下。
关于java - grpc服务器启动时,大量的io.netty.buffer.PoolThreadCache $ MemoryRegionCache $ Entry实例,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32537965/