您的位置:首页 > 其它

一次关于Netty+Gson造成内存泄露的分析排查

2016-07-12 22:36 483 查看
最近做了一个内部系统之间的数据同步服务器,client端通过socket发送经过压缩的json数据到server端,server完成数据解码和保存。server架构:netty+Gson解码
 

在做压力测试的时候,竟然发现server内存泄露。分析内存泄露的时候,其实我们可以从简单方法入手,因为jdk1.6后自身就带有不错的内存分析工具,而且我认为使用好这些工具基本足够高,因为如果你对这些工具的理解不深入,即使再强大的工具也是对你帮助不大。

 

开始分析:

 

第一步:jmap -heap <pid> 看个内存快照

 

 using thread-local object allocation.

Parallel GC with 4 thread(s)

Heap Configuration:

   MinHeapFreeRatio = 40

   MaxHeapFreeRatio = 70

   MaxHeapSize      = 536870912 (512.0MB)

   NewSize          = 1310720 (1.25MB)

   MaxNewSize       = 17592186044415 MB

   OldSize          = 5439488 (5.1875MB)

   NewRatio         = 2

   SurvivorRatio    = 8

   PermSize         = 21757952 (20.75MB)

   MaxPermSize      = 67108864 (64.0MB)

   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:

PS Young Generation

Eden Space:

   capacity = 160563200 (153.125MB)

   used     = 131079984 (125.00761413574219MB)

   free     = 29483216 (28.117385864257812MB)

   81.63762555803571% used

From Space:

   capacity = 9175040 (8.75MB)

   used     = 0 (0.0MB)

   free     = 9175040 (8.75MB)

   0.0% used

To Space:

   capacity = 9043968 (8.625MB)

   used     = 0 (0.0MB)

   free     = 9043968 (8.625MB)

   0.0% used

PS Old Generation

   capacity = 357957632 (341.375MB)

   used     = 357954568 (341.37207794189453MB)

   free     = 3064 (0.00292205810546875MB)

   99.9991440327776% used

PS Perm Generation

   capacity = 25690112 (24.5MB)

   used     = 25614800 (24.428176879882812MB)

   free     = 75312 (0.0718231201171875MB)

   99.70684440768495% used

10160 interned Strings occupying 880136 bytes.

经过一段时间运行,内存老生代满了,而且一直释放不了。

结合jcosonle运行图会更直观

 

  


 

这时候,再结合命令:jstat -gcutil <pid>  10000 20查看内存使用和回收快照,发现几十次大量的轻回收和全回收,轻回收每次时间达到2秒。

 

 

 第二部:既然确定存在内存泄露,那么就定位谁泄露,这一般是最难的地方。使用命令:jmap -histo <pid>

 

 num     #instances         #bytes  class name

----------------------------------------------

   1:       1186682       85441104  java.lang.reflect.Field

   2:       1186506       56952288  com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1

   3:       1271453       50858120  java.util.LinkedHashMap$Entry

   4:        733627       38708968  [C

   5:       1268334       30440016  com.google.gson.reflect.TypeToken

   6:        437746       29974120  [I

   7:        215160       22299464  [Ljava.util.HashMap$Entry;

   8:        122745       17675280  java.text.DecimalFormat

   9:        191610       14843680  [Ljava.lang.Object;

  10:        122746       13747552  java.util.GregorianCalendar

  11:        122746       11783616  sun.util.calendar.Gregorian$Date

  12:        116114       10890136  [B

  13:        336981       10783392  java.util.HashMap$Entry

 。。。。。

Total      11229733      542330424

就凭前两句,我大概断定是gson的问题。产生了大量gson的类。

   1:       1186682       85441104  java.lang.reflect.Field
   2:       1186506       56952288  com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1

但是,我是不会怀疑是gson的问题,而是在思考是不是使用方式不正确。

 

 

第三部:代码分析

 

gson是放在decoder里面对报文进行解码的

 

Java代码  


out.add(new Gson().fromJson(new String(beanBytes), Trade.class));  

 

 

这里省略1万字各种测试对比,反正最后结果改成这样:

 

Java代码  


private static final Gson gson = new Gson();//做成单例  
......  
out.add(gson.fromJson(new String(beanBytes), Trade.class));  

 

 

第四部:压测验证结果

 

 

 


 

 

 从图片显而易见,没有内存泄露,最后那一条下坠的横线,是我为了确认问题,做了一次全回收,回收后,内存释放到只有20多M,非常好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: