MySQL OOM 系列一 Linux内存分配

RDS(网易云关系数据库服务)上线已经有一段时间,陆续不断有产品迁入到了RDS中,在线上运维的过程中,也遇到了一些曾经没有考虑到,或者考虑的不全的东西。后续有时间可以分享给大家。

今天想提到的是线上一个4G的RDS实例,发生了OOM(out of memory)的问题,MySQL进程被直接Kill掉了。在解释这个问题的时候,我们首先需要从Linux系统内存分配策略讲起。
    一般写C语言程序,我们习惯使用malloc动态的申请内存空间(Java由JVM负责内存管理),malloc函数会向操作系统申请一段连续的内存单元,然后返回这段空间的起始地址。如果malloc函数返回为null则表示系统没有可分配的内存空间。这是我们的一般思维,当然这在某些操作系统中确实也是正确的(Solaris)。
     但是Linux不是这样的,Linux的内存分配采取的是一种更加积极的分配策略,它假设应用申请了内存空间后并不会立即去使用它,所以允许一定量的超售,当应用真的需要使用它的时候,操作系统可能已经通过回收了其他应用的内存空间而变得有能力去满足这个应用的需求,简单的说,就是允许应用申请比实际可分配空间(包括物理内存和Swap)更多的内存,这个特性称为OverCommit。
      这个特性在Linux操作系统里面也是可配的,可以通过设置/proc/sys/overcommit_memory为不同的值来调整OverCommit策略。
     overcommit_memory可以取3个值:
0:默认值,由Linux内核通过一些启发式算法来决定是否超售和超售的大小,一般允许轻微的超售,拒绝一些明显不可能提供的请求,同时做一些规则限制,比如不同用户overcommit的大小也不一样。
1:允许,不做限制的超售,当然这个也不是无限大,还受到寻址空间的限制,32位系统最大可能只有4G,64位系统大概16T左右。
2:禁止,禁止超售,系统能够分配的内存不会超过swap+实际物理内存*overcommit_ratio,该值可以通过/proc/sys/vm/overcommit_ratio设置,默认50%。

为了验证Linux的内存分配,我们用个小程序来测试一下:

#include <stdio.h>
#include <stdlib.h>
#define MEGABYTE 1024*1024
int main(int argc, char *argv[])
{
    void *myblock = NULL;
    int count = 0;

    while (1)
    {
        myblock = (void *) malloc(MEGABYTE);
        if (!myblock) break;
        printf("Currently allocating %d MB\n", ++count);
    }

    exit(0);
}

#include <stdio.h>
#include <stdlib.h>

#define MEGABYTE 1024*1024

int main(int argc, char *argv[])
{
    void *myblock = NULL;
    int count = 0;

    while(1)
    {
        myblock = (void *) malloc(MEGABYTE);
        if (!myblock) break;
        memset(myblock,1, MEGABYTE);
        printf("Currently allocating %d MB\n",++count);
    }
    exit(0);

}

前者再通过malloc()申请了内存空间以后,并没有立即去使用它,而后者相反,每次申请完都立即用1去填充。我们来看看两个程序运行的结果。

这是在1G的RAM,400M Swap的虚拟机上运行的结果,前者申请了远远超过实际内存的空间,后者并没有超过实际内存可用空间。这就验证了前面叙述的Linux的内存分配策略。
本身这是一个系统的优化,无可厚非。但是我们知道,但凡“超售”都是基于不会有大量程序同时使用资源的假设,这显然也是有风险的。所以Linux又使用了一种OOM Killer(Out Of Memory killer)的机制,在系统可用内存(包括Swap)即将使用完之前,选择性的Kill掉一些进程以求释放一些内存。下一章我们重点讨论一下Linux OOM Killer的机制。

(0)

相关推荐

  • MySQL OOM 系列三 摆脱MySQL被Kill的厄运

    前面两章,我们分析了Linux内存分配的策略以及Linux通过使用 OOM_Killer的机制解决了"超售"引起的风险,MySQL同其他的应用程序一样,在操作系统允许的范围内也是可以超售的,一般人理解,Innodb_buffer_pool必须小于实际物理内存,否则MySQL会启动失败.其实这是一个误区,这个不是MySQL层控制的,这个是操作系统(OS)层控制的,就是前面提到的/proc/sys/overcommit_memory控制OS是否允许"超售".如果允许&q

  • MySQL OOM 系统二 OOM Killer

    这里就涉及到一个问题,到底Kill掉谁呢?一般稍微了解一些Linux内核的同学第一反应是谁用的最多,就Kill掉谁.这当然是Linux内核首先考虑的一种重要因素,但是也不完全是这样的,我们查一些Linux的内核方面的资料,可以知道其实Kill谁是由/proc/<pid>/oom_score来决定的,这个值每个进程一个,是由Linux内核的oom_badness()函数负责计算的.那下面我们来仔细读一读badness()函数. 在badness()函数的注释部分,写明了badness()函数的处

  • MySQL OOM 系列一 Linux内存分配

    RDS(网易云关系数据库服务)上线已经有一段时间,陆续不断有产品迁入到了RDS中,在线上运维的过程中,也遇到了一些曾经没有考虑到,或者考虑的不全的东西.后续有时间可以分享给大家. 今天想提到的是线上一个4G的RDS实例,发生了OOM(out of memory)的问题,MySQL进程被直接Kill掉了.在解释这个问题的时候,我们首先需要从Linux系统内存分配策略讲起.     一般写C语言程序,我们习惯使用malloc动态的申请内存空间(Java由JVM负责内存管理),malloc函数会向操作

  • MySQL OOM(内存溢出)的解决思路

    OOM全称"Out Of Memory",即内存溢出. 内存溢出已经是软件开发历史上存在了近40年的"老大难"问题.在操作系统上运行各种软件时,软件所需申请的内存远远超出了物理内存所承受的大小,就叫内存溢出. 内存溢出产生原因多种多样,当内存严重不足时,内核有两种选择: 直接panic 杀掉部分进程,释放一些内核. 大部分情况下,会杀掉导致OOM的进程,然后系统恢复.通常我们会添加对内存的监控报警,例如:当memory或swap使用超过90%时,触发报警通知,需要及

  • java 进程是如何在Linux服务器上进行内存分配的

    众所周知,Java进程在启动的时候我们可以通过 -Xms 和-Xmx来设置内存的上限和下限.直到我发现使用top命令监控的Java进程在-Xms设置4g的情况下占用的内存并不是4g,这就产生了一个疑问Linux服务器的内存到底是如何进行分配的. 于是乎,我查阅了一些知乎,课程以及Linux相关的书籍.这里分享并记录的一下相关的知识. 在Linux上运行的进程不仅限于Java.都有一个概念,逻辑内存(Logic Memory),而物理机真是持有的内存,我们称为 物理内存(Physic Memory

  • Android 虚拟机中的内存分配与OOM问题详解

    目录 背景知识 一.Android VM的内存空间 1.查看内存的API 二.Android VM内存分配流程 小结 三.出现OOM的建议解决方案 背景知识 Android中每个App默认情况下是运行在一个独立进程中的, 而这个独立进程正是从Zygote孵化出来的VM进程, 也就是说, 也就是说每个Android APP在运行时会启动一个Java虚拟机. 并且系统会给它分配固定的内存空间(手机厂商会根据手机的配置情况来对其进行调整). 一.Android VM的内存空间 Android是一个多任

  • MySQL因配置过大内存导致无法启动的解决方法

    问题描述 MySQL 启动时报错,查看错误日志有 [ERROR] InnoDB: Cannot allocate memory for the buffer pool (不能从缓存池中分配给innodb引擎需要的内存) 解决办法 需要调整 MySQL 配置文件 my.cnf 中的 innodb_buffer_pool_size.key_buffer_size 的大小设置,适当的调大内存分配,一般调整为系统内存的一半 先使用 free -m 查看下系统内存大小,查看是 1G 内存 那么 vi /e

  • Mysql精粹系列(精粹)

    关于Mysql整理的需要记忆和熟练掌握的内容 1. /* 查看操作 */ ------------------------------------------------------------------------------------------------------- 1. /* 查看操作 */ SHOW PROCESSLIST -- 显示哪些线程正在运行 SHOW VARIABLES -- 查看变量 2. /* 数据库操作 */ --------------------------

  • linux 内存管理机制详细解析

    物理内存和虚拟内存我们知道,直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存是有限的,这样就引出了物理内存与虚拟内存的概念. 物理内存就是系统硬件提供的内存大小,是真正的内存,相对于物理内存,在linux下还有一个虚拟内存的概念,虚拟内存就是为了满足物理内存的不足而提出的策略,它是利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为交换空间(Swap Space). 作为物理内存的扩展,linux会在物理内存不足时,使用交换分区的

  • Java 内存分配深入理解

    Java 内存分配深入理解 本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的学习Java.这类文章网上有很多,但大多比较零碎.本文从认知过程角度出发,将带给读者一个系统的介绍. 进入正题前首先要知道的是Java程序运行在JVM(Java  Virtual Machine,Java虚拟机)上,可以把JVM理解成Java程序和操作系统之间的桥梁,JVM实现了Java的平台无关性,由此可见JVM的重要性.所以在学习Java内存分配原理的时候一定要牢记这一切都是在JVM中进行的,JVM是

  • 详解MySQL InnoDB存储引擎的内存管理

    存储引擎之内存管理 在InnoDB存储引擎中,数据库中的缓冲池是通过LRU(Latest Recent Used,最近最少使用)算法来进行管理的,即最频繁使用的页在LRU列表的最前段,而最少使用的页在LRU列表的尾端,当缓冲池不能存放新读取到的页时,首先释放LRU列表尾端的页. 上面的图中,我使用8个数据页来表示队列,具体作用,先卖个关子.在InnoDB存储引擎中,缓冲池中页的默认大小是16KB,LRU列表中有一个midpoint的位置,新读取到的数据页并不是直接放入到LRU列表的首部,而是放入

随机推荐