一、问题描述
1、背景:
租户反馈,Apr 7 11:22容器出现夯死现象, 容器部署的单个java进程;
宿主机上,top显示的容器进程virt内存持续增长32G,目前messages日志没有看到oom的记录,基本是。租户其他bc7、8系统上有添加参数MALLOC_ARENA_MAX进行限制,基本维持在16G左右,目前bcoe21.10系统配置参数MALLOC_ARENA_MAX可能没有生效,导致宿主机内存碎片问题;
2、容器内部java进程的虚拟内存异常增长30g-60g
二、排查过程
1、租户三台测试K8S节点主机使用MALLOC_ARENA_MAX=4限制内存可分配块的创建、合并、回收,传参给容器,由于java线程占用64M内存无法及时释放,导致主内存区块被占满,后续java线程请求不断从其他内存块分配内存,导致内存持续增长,尝试解决办法:调整MALLOC_ARENA_MAX=1和glibc版本;
ii.三节点调整MALLOC_ARENA_MAX=1
export MALLOC_ARENA_MAX=1
参考:
https://blog.csdn.net/m0_38017860/article/details/122192243
查看虚拟内存堆栈调用详情:pmap -x 进程ID
发现有61880KB的匿名线程的内存调用
iii.结果
两台测试机156是2.28-84和157是2.28-93,内存分配参数malloc_arena_max=1可以做到局部内存块回收,容器虚拟内存至17.3G左右,但是三台测试机均出现javacore问题;
2、测试发现glibc2.28-69、glibc2.28-93、glibc2.28-97内存分配器无法做到有效限制VIRT虚拟内存,尝试调整新的tcmalloct内存分配器;
i.安装方法:
ii.k8s节点,调整容器java配置
涉及应用容器java配置的调整,用于调用libtcmalloct库;
iii.验证libtcmalloct内存分配器库的调用情况
pmap -x java进程id | grep ‘libtcmalloc.so‘
iv.三台测试机的调整详情
v.结果
经过一天的观察, 调整内存分配器后,目前java容器内存稳定17.3g,期间客户有调整jdk版本,经过业务压测没有出现javacore的问题;
三、根因
这种情况是由于业务量较大,导致glibc可分配主内存空间数占满,后续申领主内存块时,导致MALLOC_ARENA_MAX 限制的可分配最大内存空间数失效;
那么按照测试参数1是否可以解释放堆顶层线程占用内存块?有明显的效果,可以做到部分内存块回收;
通过tcmalloc内存分配器,来解决后续glibc申请主内存块不足的问题,可以做到有效回收主内存块空间,维持17.3G。
主要问题是由于客户的jdk版本问题,jdk版本代码存在内存泄漏导致匿名内存块的持续消耗。由于栈顶java线程申领的主内存块没有释放变为匿名内存,持续占用主内存空间,导致后续java线程没有主内存块可以申领,后续非主内存持续消耗,top中查看业务线程的虚拟内存VIRT的异常消耗(32G~60G),通过安装tcmalloct内存分配器,可以有效的限制java线程的VIRT申领维持在17.3G左右,后续客户调整jdk版本,观察容器加载业务后,目前java容器没有出现javacore的现象;
标签:容器,java,Glibc2.28,线程,内存,分配器,虚拟内存 From: https://www.cnblogs.com/gkhost/p/18156421