thrift 内存溢出

短信服务,运用了thrift框架。

thrift,是 Facebook 实现的一种高效的、支持多种编程语言的远程服务调用的框架。而推出最初,其存在很多问题,见以下链接

http://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/  thrift学习入门

http://yanyiwu.com/work/2014/10/17/thrift-source-code-illustration.html thrift源码解析

http://blog.csdn.net/shijun_zhang/article/details/6863836  thrift rpc 使用常见问题解答和经验

所以,thrift的client最好是以连接池来进行管理,防止过多的client同时请求带来的问题。而thrift的server的选择,则要根据要提供的服务进行选择。

对应的server(java版)主要有

1、TSimpleServer  一般仅作为测试用
2、TNonblockingServer 非阻塞式,用nio进行通信,但依然只有一个进程处理请求
3、THsHaServer   混合模式,半同步/半异步。它使用一个单独的线程来处理网络I/O,一个独立的worker线程池来处理消息。
4、TThreadedSelectorServer 允许你用多个线程来处理网络I/O。它维护了两个线程池,一个用来处理网络I/O,另一个用来进行请求的处理。当网络I/O是瓶颈的时候,        TThreadedSelectorServer比THsHaServer的表现要好
5、TThreadPoolServer 类似于线程池了,有一个专用的线程用来接受连接。一旦接受了一个连接,它就会被放入ThreadPoolExecutor中的一个worker线程里处理。但是worker线程被绑定到特定的客户端连接上,直到它关闭。

具体区别,请查看

http://blog.csdn.net/azhao_dn/article/details/8898610

http://m.blog.csdn.net/blog/hjx_1000/42779915

我们的短信服务,因为多了一家运营商,而且又分生产跟营销不同的渠道,再考虑到可扩展性,即后期会加入别的运营商,所以将短信服务进行了简单的重构。

提供两个接口,发送营销短信、发送生产短信,然后根据传入的cpid(标志着发送短信的场合),找到对应的渠道信息,再找到对应的operator,从而调用该operator对应的发送短信的方法。

未进行重构前,还一直没关注其占用内存情况,也没有报内存溢出。

重构后,一开始还比较稳定,用了几天之后,出现了内存溢出,一直到现在,出现的越来越频繁。

用 ps -aux | grep sms 查看该服务占用内存一直增加。即使gc后,也依然减少的很少。

用 jmap -histo pid > jvm.log,打印出内存中相关的内容,

num #instances #bytes class name
----------------------------------------------
1: 2179572 34873152 java.lang.Object
2: 63701 33237280 [C
3: 242114 29053680 java.net.SocksSocketImpl
4: 241711 27071632 sun.nio.ch.SocketChannelImpl
5: 241711 11602128 sun.nio.ch.SocketAdaptor
6: 30834 7792856 [B
7: 242115 7747680 java.net.Inet4Address
8: 241712 7734784 [Ljava.nio.channels.SelectionKey;
9: 45748 6613624 <constMethodKlass>
10: 45748 6231856 <methodKlass>
11: 242580 5821920 java.io.FileDescriptor
12: 241712 5801088 java.net.InetSocketAddress
13: 3993 4316064 <constantPoolKlass>
14: 242696 3883136 java.util.concurrent.atomic.AtomicInteger
15: 241712 3867392 sun.nio.ch.OptionAdaptor
16: 241712 3867392 sun.nio.ch.SocketOptsImpl$IP$TCP
17: 241711 3867376 sun.nio.ch.SocketChannelImpl$1
18: 241264 3860224 java.nio.channels.spi.AbstractInterruptibleChannel$1
19: 69769 3599896 <symbolKlass>
20: 16811 3220440 [I

除了socket相关的,基本都是char,String,int等数组之类的。

查询内存情况的相关工具介绍,参考此链接 http://blog.csdn.net/zhujiongming/article/details/8510462

用jstat -gc pid,关注gc情况,偶然间抓住了gc前后的jvm.log,进行对比后,发现socket相关的对象基本没有减少,初步怀疑thrift基于socket通信,没有关闭socket?但是后台是一个线程池,不解。还需要对thrift原理一级socket通信原理进行学习。

后来在本地跑thrift server,没有任何请求,占用内存如下图所示,顶峰时甚至达到过400-500M,而且,测试机上的thrift server也内存溢出过,请求量几乎没有。

thrift一直再监听是否有请求,占用大量内存?

可以选择jdk自带的jconsole以及jvirtualvm来监控内存使用情况,jvirtualvm可以dump出当时内存的内容,可以分析看到里面具体的信息,比如String是什么内容等。但是依然没有收获。

后来选用jprofiler,远程监控服务器,需要加入如下配置-agentpath:/data/jprofiler9/bin/linux-x64/libjprofilerti.so=port=8849,这样就可以通过8849端口,用jprofiler客户端远程监控服务器的内存情况了。

我们也可以加入gc日志,分析gc情况  -Xloggc:/data/logs/sms/gclogs/gc.log

加入堆内存溢出时,导出dump文件,保留当时内存内容 -XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=/data/logs/sms/outofmemory.hprof

jvm参数设置以及GC策略,参考此链接 http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html ,后期需要深入学习一下。

后来发现,报内存溢出时,400M的内存,只是占用了几十M?目前问题依然没有找到。

调大短信工程占用的内存之后,问题再没出现过。。
原文地址:https://www.cnblogs.com/govoid/p/5020233.html