/**
* @author wangdaopo
* @email [email protected]
*/
理解了这个算法我们就理解了为啥 MySQL 躺着也能中枪了,因为它的体积总是最大(一般来说它在系统上占用内存最多),所以如果 Out of Memeory (OOM) 的话总是不幸第一个被 kill 掉。解决这个问题最简单的办法就是增加内存,或者想办法优化 MySQL 使其占用更少的内存,除了优化 MySQL 外还可以优化系统,让系统尽可能使用少的内存以便应用程序(如 MySQL) 能使用更多的内存,还有一个临时的办法就是调整内核参数,让 MySQL 进程不容易被 OOM killer 发现
一、什么是OOM,为什么会OOM
这通常是因为某时刻应用程序大量请求内存导致系统内存不足造成的,这通常会触发 Linux 内核里的 Out of Memory (OOM) killer,OOM killer 会杀掉某个进程以腾出内存留给系统用,不致于让系统挂掉。
因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error(注:非exception,因为这个问题已经严重到不足以被应用处理)。
1)分配的少了:比如虚拟机本身可使用的内存(一般通过启动时的VM参数指定)太少。操作系统层面
2)应用用的太多,并且用完没释放,浪费了。此时就会造成内存泄露或者内存溢出。
内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人用。
内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出。
二、OOM问题排查:
1)如果检查相关的日志文件(/var/log/messages)就会看到下面类似的 Out of memory: Kill process 信息:
下面这个 bash 脚本可用来打印当前系统上 oom_score 分数最高(最容易被 OOM Killer 杀掉)的进程:
# vi oomscore.sh
#!/bin/bash
for proc in $(find /proc -maxdepth 1 -regex '/proc/[0-9]+'); do
printf "%2d %5d %s\n" \
"$(cat $proc/oom_score)" \
"$(basename $proc)" \
"$(cat $proc/cmdline | tr '\0' ' ' | head -c 50)"
done 2>/dev/null | sort -nr | head -n 10
# chmod +x oomscore.sh
# ./oomscore.sh
18 981 /usr/sbin/mysqld
4 31359 -bash
4 31056 -bash
1 31358 sshd: root@pts/6
1 31244 sshd: vpsee [priv]
1 31159 -bash
1 31158 sudo -i
1 31055 sshd: root@pts/3
1 30912 sshd: vpsee [priv]
1 29547 /usr/sbin/sshd -D
2)由于故障已自动恢复,无法知道问题原因。只能写了个脚本代码python在最下面参考处,定时检查服务器内存情况,如果有问题就dump内存和线程信息。
OOM分析--heapdump
设定当发生OOM时自动dump出堆信息。
dump堆内存信息后,需要对dump出的文件进行分析,从而找到OOM的原因。
分析dump文件:首先,找出引用在哪里被持有;其次,给你的web应用程序添加一个关闭的hook,或者在应用程序卸载后移除引用。你可以使用如下命令导出dump文件:
如果是你自己代码的问题请及时修改,如果是第三方库,请试着搜索一下是否存在"关闭"接口,如果没有给开发者提交一个bug或者issue吧。
在开发过程中,难免会遇到程序运行过程中异常退出的情况,这时候想要定位哪里出了问题,仅仅依靠程序自身的信息打印(日志记录)往往是不够的,这个时候就需要 Core Dump 文件来帮忙了。
一个完整的 Core Dump 文件实际上相当于恢复了异常现场,利用 Core Dump 文件,可以查看到程序异常时的所有信息,变量值、栈信息、内存数据,程序异常时的运行位置(甚至记录代码行号)等等,定位所需要的一切信息都可以从 Core Dump文件获取到,能够非常有效的提高定位效率。
在linux平台下,设置core dump文件生成的方法:
1 )如何生成 coredump 文件 ?
如果 ulimit -c 0 则也是禁止产生 core 文件,而 ulimit -c 1024 则限制产生的 core 文件的大小不能超过 1024kb.
可以使用参数unlimited,取消该限制 ulimit -c unlimited
登陆 LINUX 服务器,任意位置键入 echo "ulimit -c 1024" >> /etc/profile
键入 ulimit -c
如果显示 1024 那么说明 coredump 已经被开启。1024 限制产生的 core 文件的大小不能超过 1024kb,
设置 Core Dump 的核心转储文件目录和命名规则
/proc/sys/kernel/core_uses_pid 可以控制产生的 core 文件的文件名中是否添加 pid 作为扩展 ,如果添加则文件内容为 1 ,否则为 0
proc/sys/kernel/core_pattern 可以设置格式化的 core 文件保存位置或文件名 ,比如原来文件内容是 core-%e
可以这样修改 :
echo "/corefile/core-%e-%p-%t" > core_pattern
将会控制所产生的 core 文件会存放到 /corefile 目录下,产生的文件名为 core- 命令名 -pid- 时间戳
以下是参数列表 :
%p - insert pid into filename 添加 pid
%u - insert current uid into filename 添加当前 uid
%g - insert current gid into filename 添加当前 gid
%s - insert signal that caused the coredump into the filename 添加导致产生 core 的信号
%t - insert UNIX time that the coredump occurred into filename 添加 core 文件生成时的 unix 时间
%h - insert hostname where the coredump happened into filename 添加主机名
%e - insert coredumping executable name into filename 添加命令名
一个小方法来测试产生 core 文件
直接输入指令 :
kill -s SIGSEGV $$
发生doredump一般都是在进程收到某个信号的时候,Linux上现在大概有60多个信号,可以使用 kill -l 命令全部列出来。
上述内容只是产生coredump的必要条件,而非充分条件。要产生core文件还依赖于程序运行的shell,可以通过ulimit -a命令查看,输出内容大致如下
看到第一行了吧,core file size,这个值用来限制产生的core文件大小,超过这个值就不会保存了。
总结一下,需要定位进程挂在哪一行我们只需要4个操作,
ulimit -c unlimited //echo "ulimit -c unlimited " >> /etc/profile
echo "/tmp/core-%e-%p" > /proc/sys/kernel/core_pattern
gcc -o main -g a.c
gdb main /tmp/core-main-10815
就可以啦。
3)对于内存泄露,需要通过内存监控软件查找程序中的泄露代码 常用的工具有:部署valgrind并用valgrind分析, 检测是否definite的内存泄露,当然运用好Debuggers, profilers, heap dump analyzers等工具,可以让你的程序最大程度的避免内存泄漏问题。 要记得还有profilers和memory dump analyzers这些工