mlock家族:锁定物理内存

转载自http://blog.sina.com.cn/s/blog_515b90d00100ot61.html

锁住内存是为了防止这段内存被操作系统swap掉。并且由于此操作风险高,仅超级用户可以执行。

看家族成员:

       #include <sys/mman.h>

       int mlock(const void *addr, size_t len);

       int munlock(const void *addr, size_t len);

       int mlockall(int flags);

       int munlockall(void);

 

    系统调用 mlock 家族允许程序在物理内存上锁住它的部分或全部地址空间。这将阻止Linux 将这个内存页调度到交换空间(swap space),即使该程序已有一段时间没有访问这段空间。

一个严格时间相关的程序可能会希望锁住物理内存,因为内存页面调出调入的时间延迟可能太长或过于不可预知。安全性要求较高的应用程序可能希望防止敏感数据被换出到交换文件中,因为这样在程序结束后,攻击者可能从交换文件中恢复出这些数据。

     锁定一个内存区间只需简单将指向区间开始的指针及区间长度作为参数调用 mlock。Linux 分配内存到页(page)且每次只能锁定整页内存,被指定的区间涉及到的每个内存页都将被锁定。getpagesize 函数返回系统的分页大小,在 x86 Linux 系统上,这个值是 4KB。

简单的测试程序:

#include<unistd.h>
#include<stdio.h>

int main()
{
        int i = getpagesize();
        printf("page size = %d.\n",i);
        return 0;
}

 

举个例子来说,分配 32Mb 的地址空间并把它锁进内存中,您需要使用如下的代码:

const int alloc_size = 32 * 1024 * 1024; char* memory = malloc (alloc_size); mlock (memory, alloc_size);

需注意的是,仅分配内存并调用 mlock 并不会为调用进程锁定这些内存,因为对应的分页可能是写时复制(copy-on-write)的5。因此,你应该在每个页面中写入一个假的值:

size_t i; size_t page_size = getpagesize (); for (i = 0; i < alloc_size; i += page_size) memory[i] = 0;

这样针对每个内存分页的写入操作会强制 Linux 为当前进程分配一个独立、私有的内存页。

要解除锁定,可以用同样的参数调用 munlock。

如果你希望程序的全部地址空间被锁定在物理内存中,请用 mlockall。这个系统调用接受一个参数;如果指定 MCL_CURRENT,则仅仅当前已分配的内存会被锁定,之后分配的内存则不会;MCL_FUTURE 则会锁定之后分配的所有内存。使用 MCL_CURRENT|MCL_FUTURE 将已经及将来分配的所有内存锁定在物理内存中。

锁定大量的内存,尤其是通过 mlockall,对整个系统而言可能是危险的。不加选择的内存加锁会把您的系统折磨到死机,因为其余进程被迫争夺更少的资源的使用权,并且会更快地被交换进出物理内存(这被称之为 thrashing)。如果你锁定了太多的内存,Linux 系统将整体缺乏必需的内存空间并开始杀死进程。

出于这个原因,只有具有超级用户权限的进程才能利用 mlock 或 mlockall 锁定内存。如果一个并无超级用户权限的进程调用了这些系统调用将会失败、得到返回值 -1 并得到 errno 错误号 EPERM。

munlock 系统调用会将当前进程锁定的所有内存解锁,包括经由 mlock 或 mlockall 锁定的所有区间。

一个监视程序内存使用情况的方便方法是使用top命令。在top的输出中,SIZE显示了每个程序的虚地址空间的大小(您的整个程序代码、数据、栈,其中一些应该已被交换出到交换区间)。RSS 列(Resident set size,持久集合大小)显示了程序所占用的的物理内存大小。所有当前运行程序的 RSS 数值总和不会超过您的计算机物理内存大小,并且所有地址空间的大小限制值为2GB(对于32字节版本的Linux来说)

如果您使用了mlock系统调用,请引入<sys/mman.h>头文件。

5 Copy-on-write 写时复制意味着仅当进程在内存区间的任意位置写入内容时,Linux 系统才会为进程创建该区内存的私有副本。

 

给一段示例程序:

#include<stdio.h>
#include<stdlib.h>
#include<sys/mman.h>

const int alloc_size = 32 * 1024 * 1024;//分配32M内存
int main()
{
        char *memory = malloc(alloc_size);
        if(mlock(memory,alloc_size) == -1) {
                perror("mlock");
                return (-1);
        }
        size_t i;
        size_t page_size = getpagesize();
        for(i=0;i<alloc_size;i+=page_size) {
                printf("i=%zd\n",i);
                memory[i] = 0;
        }

        if(munlock(memory,alloc_size) == -1) {
                perror("munlock");
                return (-1);
        }

        return 0;
}

记住用root权限执行。


以下转载自http://zhongcong386.blog.163.com/blog/static/13472780420111034548877/

通过mlock可以将进程使用的部分或者全部的地址空间锁定在物理内存中,防止其被交换到swap空间。
对时间敏感的应用会希望全部使用物理内存,提高数据访问和操作的效率。
例如,memcached就提供锁定内存的选项,保证memcached使用内存全部在物理内存中。

内存是宝贵,也是有限的,将地址空间全部锁定在内存中是有危险的。
当锁定的地址空间比较大的时候,为了得到足够的物理内存,linux可能会干掉一些进程,回收内存。
所有mlock操作只能root用户进行。




NAME
mlock, munlock, mlockall, munlockall – lock and unlock memory
SYNOPSIS
#include <sys/mman.h>
int mlock(const void *addr, size_t len);
int munlock(const void *addr, size_t len);
int mlockall(int flags);
int munlockall(void);



mlock主要有上面四个函数,mlock和mlockall用来锁定地址空间,munlock和munlockall用来释放锁定。




#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int mall_num = atoi(argv[1]);
char *lock_mem = argv[2];
char *t;
if(strcmp(lock_mem,”true”) == 0) {
int res = mlockall(MCL_CURRENT | MCL_FUTURE);
if (res != 0) {
printf(“warning: -k invalid, mlockall() failed: %s\n”,strerror(errno));
}
}
t = (char *) calloc(mall_num,1048576);
memset(t,0,sizeof(t));
while(1)
;
return 0;
}

用上面的代码来测试下mlock,两个参数,参数1是申请的内存大小,单位是M;参数2是地址锁定标志。
使用的是mlockall函数,后面的参数表示不仅锁定当前的地址空间,也要锁定将来申请的地址空间。

首先测试下不锁定地址空间的情况,查看内存占用通过top命令。




[hjl@sunwg test00]$ free
total used free shared buffers cached
Mem: 515340 109408 405932 0 4836 69248
-/+ buffers/cache: 35324 480016
Swap: 1048568 20812 1027756

当前系统的物理内存为512M,而交换空间为1G。

测试1,申请内存100M,不锁定内存


[hjl@sunwg test00]$ ./test.bin 100 false
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
536 hjl 25 0 101m 100m 260 R 50.0 19.9 0:12.12 test.bin



内存使用101m,其中物理内存100m

测试2,申请内存400M,不锁定内存


[hjl@sunwg test00]$ ./test.bin 400 false
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
539 hjl 25 0 401m 400m 260 R 49.9 79.5 0:08.53 test.bin



内存使用401m,其中物理内存400m

测试3,申请内存800M,不锁定内存


[hjl@sunwg test00]$ ./test.bin 800 false
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
547 hjl 25 0 801m 467m 60 R 94.0 92.9 0:07.22 test.bin



内存使用801m,其中物理内存467m,swap空间=801 – 467=334m
此时,物理内存不够用,会将一些内存交换到swap中

测试4,申请内存100M,锁定内存


[root@sunwg test00]# ./test.bin 100 true
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
582 root 25 0 101m 101m 1388 R 99.9 20.2 0:05.82 test.bin



使用内存101m,均在物理内存中

测试5,申请内存400M,锁定内存


[root@sunwg test00]# ./test.bin 400 true
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
585 root 25 0 401m 401m 1388 R 99.9 79.8 0:09.62 test.bin



使用内存401m,均在物理内存中

测试6,申请内存800M,锁定内存

[root@sunwg test00]# ./test.bin 800 true

这时候没有申请成功,系统差点挂了,因为总的物理内存才512M。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值