Cannot allocate memory报错排查记录
问题背景
应用程序打不开,通过ssh登陆进入机器发现进不去机器,重启机器之后开始对机器进行排查
排查步骤
- 查看free 和 top 发现并无异常情况
- 查看机器的监控,各个指标正常,无异常情况
- 通过"grep 'Out of memory' /var/log/messages" 和"grep -i 'memory leak' messages"发现java程序并无内存溢出和内存泄露情况
- 查看message日志没有发现相关报错
- 查看journalctl日志,通过命令 journalctl --since "2025-02-06 20:00:00" --until "2025-02-07 9:50:00" 查看到报错:Cannot allocate memory
Cannot allocate memory报错一般有两种情况:
(1)内存确实不够,无法分配内存,我这个情况内存正常。
(2)总进程数+线程数达到了默认的pid_max(32768),系统无法分配新的进程给应用程序,包括ssh。
kernel.pid_max 这个内核参数定义的是系统中允许的最大进程 ID(PID)值,它并不专门区分进程和线程,在统计时实际上是包含了线程的,系统在创建新的进程或者线程时,会从可用的 PID 池中挑选一个未被使用的 PID 分配给它们。当系统中进程和线程的总数不断增加,PID 分配逐渐接近 kernel.pid_max 时,新的进程或线程就可能无法再获取到有效的 PID,进而导致创建失败。 - 查看系统pid_max值,默认为32768:sysctl kernel.pid_max
- 查看系统内部总进程+线程数:pstree -p | wc -l 或者 ps -efL | wc -l
查看到java线程数一直在增加,由于机器已经重启,机器故障时的数量已经看不到了。
解决办法
先临时修改下最大打开进程+线程数,并且定时任务每3分钟打印当前的总数到一个文件里面,方便再出问题的时候溯源查看
# 临时增加总进程数:
sysctl -w kernel.pid_max=65535
# 永久修改总进程数,使配置立即生效:
echo "kernel.pid_max = 65535" >> /etc/sysctl.conf
sysctl -p
之后联系开发协助排查线程数为何会一直增高。
补充
内存溢出: 指的是当程序需要的内存超过了系统所能提供的内存时,会发生内存溢出。通常情况下,这种情况会导致程序崩溃或者进程被杀死。
内存泄露: 指的是程序中已经不再需要使用的对象或内存空间却没有被释放,导致这些资源一直被占用,最终导致系统内存耗尽。内存泄露通常会导致程序变慢、崩溃或者死机。