您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
Java应用堆外内存泄露问题排查
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
Java应用堆外内存泄露问题排查
fl****
2023-08-10
IP归属:北京
8880浏览
## 问题是怎么发现的 最近有个java应用在做压力测试 压测环境配置: CentOS系统 4核CPU 8g内存 jdk1.6.0_25,jvm配置-server -Xms2048m -Xmx2048m 出现问题如下 执行300并发,压测持续1个小时后内存使用率从20%上升到100%,tps从1100多降低到600多。 ## 排查问题的详细过程 首先使用top命令查看内存占用如下 ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-07-11-10-20zvbSzkJ10riXZu0o.png) 然后查看java堆内存分布情况,查看堆内存占用正常,jvm垃圾回收也没有异常。 ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-07-11-10-20418Xp7O9hOcTcRt9.png) 然后想到了是堆外内存泄漏,由于系统中用的jsf接口比较多,底层都是依赖的netty。 * 首先考虑的是java中nio包下的DirectByteBuffer,可以直接分配堆外内存,不过该类分配的内存也有大小限制的,可以直接通过-XX:MaxDirectMemorySize=1g 进行指定,并且内存不够用的时候代码中会显式的调用System.gc()方法来触发FullGC,如果内存还是不够用就会抛出内存溢出的异常。 * 为了验证这一想法,于是在启动参数中通过-XX:MaxDirectMemorySize=1g指定了堆外内存大小为1g,然后再次进行压测,发现内存还是在持续增长,然后超过了堆内存2g和堆外内存1g的总和,并且也没有发现有内存溢出的异常,也没有频繁的进行FullGC。所以可能不是nio的DirectByteBuffer占用的堆外内存。 为了分析堆外内存到底是谁占用了,不得不安装google-perftools工具进行分析。它的原理是在java应用程序运行时,当调用malloc时换用它的libtcmalloc.so,这样就能做一些统计了。 安装步骤如下: * 下载http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99-beta.tar.gz, * ./configure * make * sudo make install //需要root权限 * 下载http://google-perftools.googlecode.com/files/google-perftools-1.8.1.tar.gz, * ./configure --prefix=/home/admin/tools/perftools --enable-frame-pointers * make * sudo make install //需要root权限 * 修改lc\_config: sudo vi /etc/ld.so.conf.d/usr-local\_lib.conf,加入/usr/local/lib(libunwind的lib所在目录) * 执行sudo /sbin/ldconfig,使libunwind生效 * 在应用程序启动前加入: * export LD\_PRELOAD=/home/admin/tools/perftools/lib/libtcmalloc.so * export HEAPPROFILE=/home/admin/heap/gzip * 启动应用程序,此时会在/home/admin/heap下看到诸如gzip\_pid.xxxx.heap的heap文件 * 使用/home/admin/tools/perftools/bin/pprof --text $JAVA\_HOME/bin/java test\_pid.xxxx.heap来查看 * /home/admin/tools/perftools/bin/pprof --text $JAVA\_HOME/bin/java gzip\_22366.0005.heap > gzip-0005.txt * 然后查看分析结果如下 ```plaintext Total: 4504.5 MB 4413.9 98.0% 98.0% 4413.9 98.0% zcalloc 60.0 1.3% 99.3% 60.0 1.3% os::malloc 16.4 0.4% 99.7% 16.4 0.4% ObjectSynchronizer::omAlloc 8.7 0.2% 99.9% 4422.7 98.2% Java_java_util_zip_Inflater_init 4.7 0.1% 100.0% 4.7 0.1% init 0.3 0.0% 100.0% 0.3 0.0% readCEN 0.2 0.0% 100.0% 0.2 0.0% instanceKlass::add_dependent_nmethod 0.1 0.0% 100.0% 0.1 0.0% _dl_allocate_tls 0.0 0.0% 100.0% 0.0 0.0% pthread_cond_wait@GLIBC_2.2.5 0.0 0.0% 100.0% 1.7 0.0% Thread::Thread 0.0 0.0% 100.0% 0.0 0.0% _dl_new_object 0.0 0.0% 100.0% 0.0 0.0% pthread_cond_timedwait@GLIBC_2.2.5 0.0 0.0% 100.0% 0.0 0.0% _dlerror_run 0.0 0.0% 100.0% 0.0 0.0% allocZip 0.0 0.0% 100.0% 0.0 0.0% __strdup 0.0 0.0% 100.0% 0.0 0.0% _nl_intern_locale_data 0.0 0.0% 100.0% 0.0 0.0% addMetaName ``` 可以看到是Java\_java\_util\_zip\_Inflater\_init这个函数一直在进行内存分配,查看java源码原来是 ```java public GZIPInputStream(InputStream in, int size) throws IOException { super(in, new Inflater(true), size); usesDefaultInflater = true; readHeader(in); } ``` 原来是java中gzip解压缩类耗尽了系统内存,然后跟踪源码到了系统里边使用的jimdb客户端SerializationUtils类,jimdb客户端使用该工具类对保存在jimdb中的key和对象进行序列化和反序列化操作,并且在对Object类型的进行序列化和反序列化的时候用到了gzip解压缩,也就是在调用jimdb客户端的getObject和setObject方法时,内部会使用java的GZIPInputStream和GZIPOutputStream解压缩功能,当大并发进行压测的时候,就会造成内存泄漏,出现内存持续增长的问题,当压测停止后,内存也不会释放。 ## 如何解决问题 1、升级jdk版本为jdk7u71 ,压测一段时间后,发现内存增长有所减慢,并且会稳定在一定的范围内,不会把服务器的所有内存耗尽。猜测可能是jdk1.6版本的bug 2、尽量不要使用jimdb客户端的getObject和setObject方法,如果真的需要保存对象,可以自己实现序列化和反序列化,不要解压缩功能,因为对象本来就不大,压缩不了多少空间。如真的需要解压缩功能,最好设置解压缩阀值,当对象大小超过阀值之后在进行解压缩处理,不要将所有对象都进行解压缩处理。
上一篇:这篇深入浅出贴 助你早日实现Stable diffusion自由
下一篇:Log4j疯狂写日志问题排查
fl****
文章数
11
阅读量
2879
作者其他文章
01
千万级数据深分页查询SQL性能优化实践
一、系统介绍和问题描述 如何在Mysql中实现上亿数据的遍历查询?先来介绍一下系统主角:关注系统,主要是维护京东用户和业务对象之前的关注关系;并对外提供各种关系查询,比如查询用户的关注商品或店铺列表,查询用户是否关注了某个商品或店铺等。但是最近接到了一个新需求,要求提供查询关注对象的粉丝列表接口功能。该功能的难点就是关注对象的粉丝数量过多,不少店铺的粉丝数量都是千万级别,并且有些大V
01
ElasticSearch - 批量更新bulk死锁问题排查
一、问题系统介绍1. 监听商品变更MQ消息,查询商品最新的信息,调用BulkProcessor批量更新ES集群中的商品字段信息;2. 由于商品数据非常多,所以将商品数据存储到ES集群上,整个ES集群共划分了256个分片,并根据商品的三级类目ID进行分片路由。比如一个SKU的商品名称发生变化,我们就会收到这个SKU的变更MQ消息,然后再去查询商品接口,将商品的最新名称查询回来,再根据这个SKU的三级
01
京东统一头尾管理系统探索实践
系统背景 问:修改一个网站的文案需要多久?对于一个小型个人网站来说,估计很简单,几分钟就能修改完成并发布。但如果说要修改的是上百个网站的文案呢?那估计就得需要产品提需求,研发排期开发,测试进行回归验证。由于涉及的应用众多,而每个应用都有自己的研发需求,可能无法快速排期进行文案修改。所以看似一个非常简单的需求,涉及到的应用和部门比较多的时候,也就成了产品经理的恶梦。尤其是像京东商城这样
01
百亿规模京东实时浏览记录系统的设计与实现
1. 系统介绍浏览记录系统主要用来记录京东用户的实时浏览记录,并提供实时查询浏览数据的功能。在线用户访问一次商品详情页,浏览记录系统就会记录用户的一条浏览数据,并针对该浏览数据进行商品维度去重等一系列处理并存储。然后用户可以通过我的京东或其他入口查询用户的实时浏览商品记录,实时性可以达到毫秒级。目前本系统可以为京东每个用户提供最近200条的浏览记录查询展示。2. 系统设计与实现2.1 系统整体架构
fl****
文章数
11
阅读量
2879
作者其他文章
01
千万级数据深分页查询SQL性能优化实践
01
ElasticSearch - 批量更新bulk死锁问题排查
01
京东统一头尾管理系统探索实践
01
百亿规模京东实时浏览记录系统的设计与实现
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号