Linux 系统上VIRT内存占用过多处理方法
一、问题描述
top查看系统进程,java进程VIRT分配过多;
系统内存占用查询
二、问题分析
1.操作系统分析:
查询Red Hat Enterprise Linux 官方有文档说明,VIRT分配过多问题, 是操作系统上 glibc 版本引入的arena 新功能导致(从glibc2.10及之后),此功能对每个线程都分配一个本地arena来加速多线程的执行,即在一个多线程程序中,就会出现相当多的64MB的arena 被分配;且从glibc2.10之后版本都提供了许多功能和增强功能,其中glibc增强的动态内存分配(malloc)行为,可跨多个套接字和内核实现更高的可扩展性。这是通过为线程分配自己的内存池以及在某些情况下避免锁定来实现的。
VIRT高是因为分配了太多虚拟地址空间导致。一般来说不用太在意VIRT太高,因为你有16EB的空间可以使用。如果实在需要控制VIRT的使用,可设置环境变量MALLOC_ARENA_MAX值进行限制。
2.java 程序分析:
Java 程序由于自己维护堆的使用,导致调用 glibc 去管理内存的次数较少。特别是 Java 8 开始使用 metaspace 原空间取代永久代,而元空间是存放在操作系统本地内存中,因此线程一多,每个线程都要使用一点元空间,每个线程都分配一个 arena,每个都64MB,就会导致巨大的虚拟地址被分配。
可以控制台上-->实例页签--->参数设置,可看到具体实例最大堆分析内存值:
此值只是java内存中heap值:
JVM在执行Java程序时,会把它管理的内存划分为若干个的区域,每个区域都有自己的用途和创建销毁时间。如下图 所示,可以分为两大部分,线程私有区和共享区;因此实际java实例内存值为分配值 +1G内存值 。
三、控制方法
1.使用MALLOC_ARENA_MAX 进行控制;
对于MALLOC_ARENA_MAX控制不住的原因,如果 MALLOC_ARENA_MAX 设置为 n,当 n 个 thread arena 的内存空间全被占满的时候,线程新申请内存的时候优先创建新的arena,不受n的限制,并且是无上限的;arena_lookup查找分配区和arena_lock锁分配区的时候并不关心该分配区的空间是否足够,如果 arena_lock 到的分配区空间不足,就创建新的thread arena函数:sysmalloc,new_heap创建新的thread arena时并不检查MALLOC_ARENA_MAX的配置值
;设置为1时,相当于禁用了 thread arena,arena_lookup每次都会返回 main arena,不会创建任何 thread arena ;
四、调整系统参数处理:
解决方法:
使用系统环境变量参数MALLOC_ARENA_MAX来控制内存池,即MALLOC_ARENA_MAX设置为1,禁用了thread arena,arena_lookup每次都会返回 main arena,不会创建任何thread arena;
(1)普通用户作为服务账号启动:在普通用户的.bash_profile中加入:export MALLOC_ARENA_MAX=1,
(2)若EAS控制台为root用户,在vi /etc/profile中最后一行下加入:export MALLOC_ARENA_MAX=1,
再source /etc/profile或者重新登录服务器终端参数生效,再重启EAS集群服务,包括控制台服务;观察VIRT值不会增长过大,并限制在一定范围。
Linux 系统上VIRT内存占用过多处理方法
本文2024-09-22 20:29:53发表“eas cloud知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-eas-114010.html