一、man mlock翻译
1. NAME
mlock、mlock2、munlock、mlockall、munlockall - 锁定和解锁内存
2. SYNOPSIS
#include <sys/mman.h> int mlock(const void *addr, size_t len); int mlock2(const void *addr, size_t len, int flags); int munlock(const void *addr, size_t len); int mlockall(int flags); int munlockall(void);
3. DESCRIPTION
mlock()、mlock2() 和 mlockall() 将调用进程的部分或全部虚拟地址空间锁定到 RAM 中,防止该内存被分页到交换区域。
munlock() 和 munlockall() 执行相反的操作,解锁调用进程的部分或全部虚拟地址空间,以便如果内核内存管理器需要,可以再次交换出指定虚拟地址范围内的页面。
内存锁定和解锁以整个页面为单位执行。
3.1 mlock()、mlock2() 和 munlock()
mlock() 锁定从 addr 开始并持续 len 字节的地址范围内的页面。当调用成功返回时,保证包含指定地址范围的一部分的所有页面驻留在 RAM 中;保证这些页面一直留在 RAM 中,直到稍后解锁。
mlock2() 还锁定从 addr 开始并持续 len 字节的指定范围内的页面。但是,调用成功返回后该范围内包含的页面的状态将取决于 flags 参数中的值。#######
flags 参数可以是 0 或以下常量:
MLOCK_ONFAULT
锁定当前驻留的页面并标记整个范围,以便当剩余的非驻留页面因page fault而填充时锁定它们。
如果 flags 为 0,mlock2() 的行为与 mlock() 完全相同。
munlock() 解锁从 addr 开始并持续 len 个字节的地址范围内的页面。 调用此函数后,内核可以再次将所有包含指定内存范围一部分的页面移动到外部交换空间。
3.2 mlockall() 和 munlockall()
mlockall() 锁定映射到调用进程地址空间的所有页面。这包括代码段、数据段和堆栈段的页面,以及共享库、用户空间内核数据、共享内存和内存映射文件。当调用成功返回时,所有映射页面都保证驻留在 RAM 中;这些页面保证一直留在 RAM 中,直到稍后解锁。
flags 参数由以下一个或多个常量的按位或构成:
MCL_CURRENT 锁定当前已映射到进程地址空间的所有页面。
MCL_FUTURE 锁定将来将映射到进程地址空间的所有页面。例如,这些页面可能是不断增长的堆和堆栈所需的新页面,以及新的内存映射文件或共享内存区域。
MCL_ONFAULT(自 Linux 4.4 起)与 MCL_CURRENT、MCL_FUTURE 或两者一起使用。标记所有当前(使用 MCL_CURRENT)或未来(使用 MCL_FUTURE)映射以在发生 fault 时锁定页面。与 MCL_CURRENT 一起使用时,所有现有页面都将被锁定,但 mlockall() 不会在非现有页面中发生fault。与 MCL_FUTURE 一起使用时,所有未来映射都将被标记为在发生fault时锁定页面,但在创建映射时不会由 lock 填充它们。 MCL_ONFAULT 必须与 MCL_CURRENT 或 MCL_FUTURE 或两者一起使用。
如果指定了 MCL_FUTURE,则后续系统调用(例如 mmap(2)、sbrk(2)、malloc(3))可能会失败,如果它会导致锁定的字节数超过允许的最大值(见下文)。在同样的情况下,堆栈增长也可能失败:内核将拒绝堆栈扩展并向进程发送 SIGSEGV 信号。
munlockall() 解锁映射到调用进程地址空间的所有页面。
4. RETURN VALUE
成功时,这些系统调用返回 0。出错时,返回 -1,errno 被适当设置,并且不对进程地址空间中的任何锁定进行任何更改。
5. ERRORS
ENOMEM(Linux 2.6.9 及更高版本)调用者具有非零的 RLIMIT_MEMLOCK 软资源限制,但试图锁定超过允许限制的内存。如果进程具有特权(CAP_IPC_LOCK),则不强制执行此限制。
# ulimit -a -l: lockedmem(KiB) 65536
ENOMEM(Linux 2.4 及更早版本)调用进程试图锁定超过一半的 RAM。
EPERM 调用者没有特权,但需要特权(CAP_IPC_LOCK)才能执行请求的操作。
对于 mlock()、mlock2() 和 munlock():
EAGAIN 无法锁定部分或全部指定地址范围。
EINVAL addr+len 的加法结果小于 addr(例如,加法可能导致溢出)。
EINVAL(非 Linux)addr 不是页面大小的倍数。
ENOMEM 部分指定地址范围与进程地址空间中的映射页面不对应。
ENOMEM 锁定或解锁某个区域会导致具有不同属性(例如,锁定与解锁)的映射总数超过允许的最大值。(例如,解锁当前锁定映射中间的范围会导致三个映射:两端各有两个锁定映射,中间有一个解锁映射。)
对于 mlock2():
EINVAL 指定了未知标志。
对于 mlockall():
EINVAL 指定了未知标志或指定了 MCL_ONFAULT,但没有 MCL_FUTURE 或 MCL_CURRENT。
对于 munlockall():
EPERM(Linux 2.6.8 及更早版本)调用者没有特权(CAP_IPC_LOCK)。
6. VERSIONS
mlock2() 自 Linux 4.4 起可用;glibc 支持已在版本 2.27 中添加。
7. CONFORMING TO
POSIX.1-2001、POSIX.1-2008、SVr4。
mlock2 () 是 Linux 特有的。
8. AVAILABILITY
在 mlock() 和 munlock() 可用的 POSIX 系统上,_POSIX_MEMLOCK_RANGE 在 <unistd.h> 中定义,页面中的字节数可以从 <limits.h> 中的常量 PAGE‐SIZE(如果已定义)或通过调用 sysconf(_SC_PAGESIZE) 确定。
在 mlockall() 和 munlockall() 可用的 POSIX 系统上,_POSIX_MEMLOCK 在 <unistd.h> 中定义为大于 0 的值。(另请参阅 sysconf(3)。)
9. NOTES
内存锁定有两个主要应用:实时算法和高安全性数据处理。实时应用程序需要确定性计时,并且与调度一样,分页是意外程序执行延迟的主要原因之一。实时应用程序通常也会使用 sched_setscheduler(2) 切换到实时调度程序。加密安全软件通常将密码或密钥等关键字节作为数据结构进行处理。分页的结果是,这些机密信息可能会转移到持久交换存储介质上,在安全软件从 RAM 中删除机密信息并终止后很长时间,敌人仍可能访问这些机密信息。(但请注意,无论内存锁定如何,笔记本电脑和某些台式电脑上的挂起模式都会将系统 RAM 的副本保存到磁盘。)
使用 mlockall() 来防止页面错误延迟的实时进程应在进入时间关键部分之前保留足够的锁定堆栈页面,以便函数调用不会导致page faults。这可以通过调用一个函数来实现,该函数分配一个足够大的自动变量(一个数组)并写入此数组占用的内存以接触这些堆栈页面。这样,将为堆栈映射足够的页面,并可以将其锁定到 RAM 中。虚拟写入确保关键部分中甚至不会发生copy-on-write page faults。
内存锁不会被通过 fork(2) 创建的子进程继承,并且在 execve(2) 期间或进程终止时会自动删除(解锁)。mlockall() MCL_FUTURE 和 MCL_FUTURE | MCL_ONFAULT 设置不会被通过 fork(2) 创建的子进程继承,并且在 execve(2) 期间会被清除。
请注意,fork(2) 将为写时复制操作准备地址空间。结果是,随后的任何写访问都将导致page fault,进而可能导致实时进程的高延迟。因此,在 mlockall() 或 mlock() 操作之后不要调用 fork(2) 至关重要——即使是在具有高优先级线程的进程中以低优先级运行的线程也不要调用。
如果通过 munmap(2) 取消映射地址范围,则会自动删除该地址范围上的内存锁。
内存锁不会堆叠,也就是说,通过调用 mlock()、mlock2() 或 mlockall() 多次锁定的页面将通过对相应范围的 munlock() 或 munlockall() 的一次调用解锁。映射到多个位置或由多个进程映射的页面只要至少在一个位置或由至少一个进程锁定,就会保持锁定在 RAM 中。
如果对使用 MCL_FUTURE 标志的 mlockall() 的调用后跟有另一个未指定此标志的调用,则 MCL_FUTURE 调用所做的更改将丢失。
mlock2() MLOCK_ONFAULT 标志和 mlockall() MCL_ONFAULT 标志允许高效地锁定内存,用于处理大型映射的应用程序,其中映射中只有一小部分页面被触及。在这种情况下,锁定映射中的所有页面将导致内存锁定的严重损失。
9.1 Linux notes
在 Linux 下,mlock()、mlock2() 和 munlock() 会自动将 addr 向下舍入到最近的页面边界。但是,mlock() 和 munlock() 的 POSIX.1 规范允许实现要求 addr 页面对齐,因此可移植应用程序应确保这一点。
Linux 特定的 /proc/[pid]/status 文件的 VmLck 字段显示 ID 为 PID 的进程使用 mlock()、mlock2()、mlockall() 和 mmap(2)MAP_LOCKED 锁定了多少千字节内存。
9.2 Limits and permission
在 Linux 2.6.8 及更早版本中,进程必须具有特权 (CAP_IPC_LOCK) 才能锁定内存,而 RLIMIT_MEMLOCK 软资源限制定义了进程可以锁定的内存量限制。
自 Linux 2.6.9 起,特权进程可以锁定的内存量不再受到限制,而是由 RLIMIT_MEMLOCK 软资源限制来定义非特权进程可以锁定的内存量限制。
10. BUGS
在 Linux 4.8 及更早版本中,内核在计算非特权进程(即没有 CAP_IPC_LOCK)的锁定内存时存在一个错误,这意味着如果 addr 和 len 指定的区域与现有锁定重叠,则在检查限制时,重叠区域中已锁定的字节会被计算两次。这种双重计算可能会错误地计算超出 RLIMIT_MEMLOCK 限制的进程的“总锁定内存”值,导致 mlock() 和 mlock2() 在本应成功的请求上失败。此错误已在 Linux 4.9 中修复。
在 2.4 系列 Linux 内核(包括 2.4.17)中,一个错误导致 mlockall() MCL_FUTURE 标志在 fork(2) 中被继承。此问题已在内核 2.4.18 中得到纠正。
自内核 2.6.9 起,如果特权进程调用 mlockall(MCL_FUTURE) 并随后放弃特权(例如,将其有效 UID 设置为非零值,从而失去 CAP_IPC_LOCK 功能),则如果遇到 RLIMIT_MEMLOCK 资源限制,后续内存分配(例如,mmap(2)、brk(2))将会失败。
11. SEE ALSO
mincore(2)、mmap(2)、setrlimit(2)、shmctl(2)、sysconf(3)、proc(5)、capabilities(7)
12. COLOPHON
此页面是 Linux man-pages 项目 4.15 版的一部分。您可以在 https://www.kernel.org/doc/man-pages/ 找到该项目的描述、有关报告错误的信息以及此页面的最新版本。
Linux 2018-02-02
参考:
man mlock: https://www.kernel.org/doc/man-pages/
标签:MCL,映射,内存,42,mlock,man,锁定,页面 From: https://www.cnblogs.com/hellokitty2/p/18539585