2.Linux内存管理----内存动态申请、释放

本文详细介绍了Linux内核态和用户态的内存申请与释放,包括slab和libc的管理机制,内核内存申请API,进程申请内存的过程,以及Linux面对内存溢出(OOM)时的处理策略。通过slabinfo可以监控内核slab状态,malloc/free由libc管理,内存分配可采用demanding page或lazy allocation方式。
摘要由CSDN通过智能技术生成

一、内核态、用户态的内存申请和释放

    Linux最底层的物理内存是通过buddy算法进行管理的,但是buddy的最小单位为页,如果我们想申请一个字节的时候,该怎么办。
     在Linux内核态中,以字节为单位的申请是通过slab算法进行管理的;用户态中是通过libc进行管理的。slab和libc相当于一个二级内存分配管理器。

    1、slab----内核态的内存申请/释放
    当Kernel从通过kmalloc申请8(假设值)字节内存时,先通过buddy申请一页的内存,然后将这一页划分成空间大小相等的份数(512份的8字节内存),每一份存称为object。然后从这些份数中去一个object分配给要申请的内核;释放的时候是通过kfree返回给slab。
    可以通过cat /proc/slabinfo来查看内核slab的分配信息。一般判断内核是否有内存泄露,可以通过slabinfo来查看是否有泄露。
    slab分为reclaim(I/O cache…) 和 unrecliam(heap…);

    2、libc(brk、mmap)----用户态的内存申请/释放
    用户态的内存申请释放是通过malloc/free来进行的,他们均由libc管理。
    在用户空间申请内存时,可以通过mallopt函数中的参数M_TRIM_THRESHOLD来指定,进程释放到指定的数值的内存后才返回给buddy,如果设置成为-1(mallopt(M_TRIM_THRESHOLD,-1)),那么当前申请的内存调用free命令后,永远也不会返回给buddy,只会返回给libc,同时返回的内存也是无法被其他进程申请的。

二、内核内存申请api

概念输入:
    vmalloc映射区 和 lowmemory映射区 是指的虚拟地址,在32位cpu当中:
    0-3G:用户空间
    3G-(3G+896M):Low memory 映射区
    (3G+896) - 4G:vmalloc映射区

内核申请内存的api:
1、vmalloc:申请物理内存,并将物理内存的地址和vmalloc映射区的地址进行映射
2、kmalloc:在lowmemory映射区申请内存并映射到物理内存地址(线性映射),
            通过phy_to_vir/vir_to_phy映射物理地址和虚拟地址。
3、ioremmap:将寄存器地址映射到vmalloc映射区

    其中,Low memory 映射区在内核启动后就已经做好线性映射了,所以kmalloc内存的时候,直接进行物理的偏移即可;但是在vmalloc内存或者ioremmap时,需要将物理内存的地址或者寄存器的地址与vmallco映射区的地址做映射后才可使用。
    也就是说vmalloc映射区包含vmalloc的内存的信息和ioremap的信息;这里可以通过执行```
cat /proc/vmallocinfo/ [| grep ioremap] 来查看vmalloc映射区的信息。

三、进程申请内存的过程

    当设备上电后,进程在首次执行 p = malloc(100M);时的过程如下:
    首先从0-3G的空间找一段空闲连续的虚拟内存,并把该虚拟内存的地址返回给p,同时创建VMA, VMA用来说明,该虚拟内存的地址范围,以及该内存的权限(假设p的地址是1G,那么他申请的大小就是1G+100M,同时这段地址范围内是RW的权限)。
    当malloc成功返回时,只能说明你成功的申请到了虚拟内存,但是这是还并未申请实际的物理内存。此时申请的全部的虚拟内存地址通过MMU都被映射到0页地址(0页:该页全部被0填充,权限为 read-only);
    如果进程,一直不对p进行 write操作,那么底层就一直不会给p申请实际的物理内存。
    如果此时进行一个写操作时,流程如下:

1、执行 p[0] = 0x01 (相当于写操作)
2、mmu发现该地址是 只能 read-only的,mmu向cpu发起 pagefault 的中断
3、在pagefault中断中,获取
  ①出问题的地址:地址合法,在VMA区域中
  ②出问题的原因:对该地址进行写操作:但是VMA中这个权限也是合理的。
4此时pagefault中断cpu就不会向进程发送segmentfaultde 信号,而是向buddy申请一页物理内存,
  并通过MMU映射到1G+0的地址,并标明该地址的权限(R+W);
5、如果进程对 p[0-4095] 数据进行操作时,都不会在申请新的物理内存,
   此时该进程的实际占的物理内存大小就只有4K;
   直到对p[4096]进行操作时,会重复1-4步骤。

    我们称呼这种内存分配方式:demanding page , lazy allocation
    同时,通过上面分析。VMA中的地址的合法范围以及对应的权限,在MMU中页表中对应的权限是不一致的。
    如果进程之前已经申请过内存,但是又释放掉了,当再次申请时,有可能是直接从libc中申请的;

四、OOM(内存溢出:Out of Memory)

    当Linux在malloc后,但是申请不到实际的物理内存时,就会产生OOM;此时Linux就会找出最该死的那个进程,并将其kill掉。
    如何找出最该死的进程:在/proc/${pid}目录下有一个oom_score的文件,这个文件中的分值越大,当OOM的时候,这个进程越被优先杀掉。
    调整oom_score分值:通过向/proc/${pid}目录下的oom_adj 和 oom_score_adj 两个文设置数值就可以调整oom_score的分值。
    如果不想启用OOM机制,可以将panic_on_oom(/proc/sys/vm/)设为1,这样内存枯竭时不再杀进程,而是操作系统崩溃.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值