文档章节

【jvm】来自于线上的fullGC分析

o
 osc_a22drz29
发布于 2019/03/21 21:34
字数 1843
阅读 8
收藏 0

精选30+云产品,助力企业轻松上云!>>>

   系统最近老年代的内存上升的比较快,三到四天会发生一波fullGC。于是开始对GC的情况做一波分析。

   线上老年代2.7G,年轻带1.3G老年代上升较快,3天一波fullGC,并且fullGC会把内存回收,有时回收一般,有时回收全部。所以判断是不会有内存泄漏现象的,内存发生泄漏是回收不了的。第二个判断,不存在大对象,一个是基于对程序的理解,一个是对于老年代上升的速率,基本是稳固上升。不存在峰值。

   我是先用jstack  命令打印出线程状态的  jstack -l pid  >> 文件名  发现这么操作是无用的。jstack主要是分析线程状态的,尤其是针对占用CPU,死循环,死锁操作等。

    一开始确实定位到一个线程,是我们服务每个一分钟拉去配置中心数据的线程,数据量很小,而且基本都是重复的数据。所以那会没有头绪方向不对。

后来老大说打下内存快照啊。于是就开始看下内存快照了。

    1、先使用 jmap命令打印出内存快照文件。

      jmap  -dump:format=b,file= 文件路径  pid(进程号)    

    2、使用MemoryAnalyzer(windows下的分析工具)工具分析大对象

    分析出来是jdbc连接对象实例太多,因为mysql的jdbc包在每次创建jdbc连接的时候,会对连接进行虚引用包装,最后放到一个ConcurrentHashMap里。而系统1分钟会进行年轻代的GC,而程序配置的链接生命周期为30分钟。所以30分钟MinGC将到达30多次,而JVM默认的配置是15。所以我们推测这个配置的不对,要么减少生命周期要么增加JVM年龄的配置。

   经过测试在jdk8的环境下,年龄的阈值是不能超过15的,这就尴尬了。于是只好降低生命周期,同时设置数据源的最大连接和最小连接相等,防止数据源一直创建空闲连接,这样能方式连接数量,同时通过反射,检测ConcurrentHashMap的数量。经过上线后,发现并没有明显效果。于是乎干脆把map的数据直接清空,发现清空了上完线也并没有解决老年代上升的问题。不过老年代每次fullGC都会回收到底。于是判断清空有助于进行回收,并且老年代回收的耗时也变短了,减少到一半时间。

    另一方面观测,检查了JVM年轻代 E区和S区的比例,你会认为默认是1:8,但是不是那么简单地。发现程序刚启动时确实是1比8,但是随着程序启动,MinGC,jvm默认的垃圾回收器会自动调节这个比例。只有设置CMS才不会自动调节。于是决策是由于S区分配内存太小导致,当时我们的S区稳定在30M左右,E区差不多有1.3G。于是改成了CMS垃圾回收器,发现也并没有卵用,而且老年代内存到达50%就发生了fullGC,看来CMS是可以设置回收阈值的。实在没办法了,只好换数据源了,把HikairCP换成了druid。发现换了之后就解决了,fullGC频率从4天能到达15天,ConcurrentMap的数量很少,最多也就2百的量。而之前能达到上万的量。总之不知道是因为HikairCP的原因,还是我们配置的原因。据说这个数据源号称比druid速度更优的数据源。

.

.

.

    历史是何其的相似,程序性能问题又来了,我们程序为了提高tps,经过压测,发现瓶颈在于redis,当时redis是哨兵模式,读写访问一个master,于是想切换为集群。发现切换为集群后,fullGC的频率又回到了原先的地步,而且把操作切换为读集群时,压力更大,竟然再短短5小时内,打满老年代内存, 并且CPU占用也较大。没办法观测了一会,发现每5分钟上升2个百分点。代码回滚了。于是乎又开始了一波分析,代码优化。

    经过分析本次上线只是添加了cluster管道批量操作的代码,代码肯定出现在这里,于是开始进行优化。

    首先分析线上内存快照,发现最大占用的是 int 数组,这个不好分析,应为属于基本对象,没法分析。于是乎私底下在本地进行读集群方法的压测,再加上代码的分析,发现每次操作都会对取cluster集群的信息,这个集群的信息包含了所有节点的ip+port,以及他们对应的分槽信息,而这个分槽信息是以LinkedHashSet类型存储的,里面是满满的Integer类型的槽。一共16384个,于是基本确定了,是每次实时查询cluster集群信息导致的。发现Jedis的方法是对集群信息做了缓存的 ,但是只缓存了100毫秒。再加上我们本身程序也包含了大量的业务逻辑。估计这么一连起来就造成了YGC次数过高,或者年轻代S区空间太小。于是从两个方面去提高程序性能。

   发现在修改JVM参数配比,提高年轻代S区的内存大小,并且修改垃圾回收器为CMS,发现在本机进行ab压测,最高tps到达了800。并且在并发80,访问量50000的情况下,老年代内存会上升到100M,YGC次数能够到达200。而哨兵的压测结果tps最高到达2000。而且老年代内存50M。YGC次数也在30以内。

于是对cluster的代码进行优化,把每次获取集群节点信息放到了for循环里。tps提高到1300,老年代内存稳定在90M。

    我们程序另一条思路是:把集群的信息缓存到JVM,不依靠Jedis的缓存100ms。而是由我们自己缓存。但是存在一个问题,每当集群节点扩容,分槽或者主下线,从上线。我们的程序就检测不到变化了,于是在程序里开启了异步线程每个5秒刷新集群信息,而且对于每次操作cluster做了重试处理,一旦检测到节点连接创建失败,发生MOVED错误,就刷新集群信息,进行操作重试。发现使用静态缓存集群信息的方式,tps提高到2000左右,基本和哨兵持平,而且老年代内存也到达60M左右,YGC次数也降下来了。

 

 在这些过程中,我学到了什么:

 自己尝试搭建了虚拟机的redis-cluster集群(很早就搭建了,这回正好用上),redis集群分槽。

 cluster管道批量操作,jdk的一些常用工具命令,还有ab的简单压测

最后重要的是分析问题的能力和思路

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
线上FullGC频繁的排查

线上FullGC频繁的排查 问题 前段时间发现线上的一个dubbo服务Full GC比较频繁,大约每两天就会执行一次Full GC。 Full GC的原因 我们知道Full GC的触发条件大致情况有以下几种情况: 程序执行...

rockypeng
2018/07/12
0
0
线上问题与排查

死锁 一文学会Java死锁和CPU 100% 问题的排查技巧 如何避免死锁,我们有什么套路可循?(举例说明,浅显生动,给出了死锁发生的Coffman条件,并从破坏条件角度讲如何避免死锁) MySQL锁总结-11.死...

KafkaPlus
05/29
5
0
JVM内存设置多大合适?Xmx和Xmn如何设置?

JVM内存设置多大合适?Xmx和Xmn如何设置? 展开 本文地址:https://www.dutycode.com/jvmxmxxmnxmsshezhi.html 除非注明,文章均为 www.dutycode.com 原创,欢迎转载!转载请注明本文地址,谢...

滴滴滴
06/11
0
0
JVM内存设置多大合适?Xmx和Xmn如何设置?

JVM内存设置多大合适?Xmx和Xmn如何设置? 问题: 新上线一个java服务,或者是RPC或者是WEB站点, 内存的设置该怎么设置呢?设置成多大比较合适,既不浪费内存,又不影响性能呢? 分析: 依据...

盗帅_tim
2019/08/12
0
0
关于GC(上):Apache的POI组件导致线上频繁FullGC问题排查及处理全过程

某线上应用在进行查询结果导出Excel时,大概率出现持续的FullGC。解决这个问题时,记录了一下整个的流程,也可以作为一般性的FullGC问题排查指导。 1. 生成dump文件 为了定位FullGC的原因,首...

osc_mblu5qn4
04/16
6
0

没有更多内容

加载失败,请刷新页面

加载更多

等到所有jQuery Ajax请求都完成了吗? - Wait until all jQuery Ajax requests are done?

问题: How do I make a function wait until all jQuery Ajax requests are done inside another function? 我如何让一个函数等到所有jQuery Ajax请求都在另一个函数中完成之后? In short...

富含淀粉
36分钟前
17
0
OSChina 周日乱弹 —— 那么长的绳子,你这是放风筝呢

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @ 巴拉迪维:黑豹乐队的单曲《无地自容》 耳畔突然响起旋律,是那首老歌。中国摇滚有了《一无所有》不再一无所有;中国摇滚有了《无地自容》不...

小小编辑
今天
65
1
《吐血整理》-顶级程序员书单集

你知道的越多,你不知道的越多 给岁月以文明,而不是给文明以岁月 前言 王潇:格局决定了一个人的梦想,梦想反过来决定行为。 那格局是什么呢? 格局是你能够看见的深度、广度和密度。 王潇认...

敖丙
2019/12/11
15
0
我可以在Android版式中加下划线吗? - Can I underline text in an Android layout?

问题: 如何在Android布局xml文件中定义带下划线的文本? 解决方案: 参考一: https://stackoom.com/question/A31z/我可以在Android版式中加下划线吗 参考二: https://oldbug.net/q/A31z/...

法国红酒甜
今天
26
0
干掉ELK | 使用Prometheus+Grafana搭建监控平台

什么是Prometheus? Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库(TSDB)。Prometheus使用Go语言开发,是Google BorgMon监控系统的开源版本。 Prometheus的特点 · 多维度...

木九天
今天
34
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部