热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

《Linux/UNIX系统编程手册》第50章虚拟内存操作

关键词:mprotect()、mlock()、mlockall()、mincore()、madvise()等等。 mprotect()修改一块虚拟内存区域上的保护信息。mlock(

关键词:mprotect()、mlock()、mlockall()、mincore()、madvise()等等。

 

mprotect()修改一块虚拟内存区域上的保护信息。

mlock()和mlockall()将一块虚拟内存区域锁进物理内存,从而防止它被交换出去。

mincore()让一个进程能够确定一块虚拟内存区域中的分页是否驻留在物理内存中。

madvise()让一个进程能够将其对虚拟内存区域中的使用模式报告给内核。


1. 改变内存保护:mprotect()

#include
int mprotect(void *addr, size_t length, int prot);
Returns
0 on success, or –1 on error

addr的取值必须是系统分页大小的整数倍。

length会被向上舍入到系统分页大小的下一个整数倍。

prot是一个位掩码,指定了这块内存区域上的心保护属性,取值可以是PROT_NONE、PROT_READ、PROT_WRITE、PROT_EXEC中一个或多个取OR。

如果一个进程在访问一块内存区域时违背了内存保护,那么内核就会向该进程发送一个SIGSEGV信号。

mprotect()一个用途是修改原先通过mmap()创建的内存映射区域上的保护

下面示例创建一块内存,然后对不同区域进行prot修改:

#define _BSD_SOURCE /* Get MAP_ANONYMOUS definition from */
#include

#include
"tlpi_hdr.h"
#define LEN (1024 * 1024)
#define SHELL_FMT "cat /proc/%ld/maps | grep zero"
#define CMD_SIZE (sizeof(SHELL_FMT) + 20)
/* Allow extra space for integer string */
int
main(
int argc, char *argv[])
{
char cmd[CMD_SIZE];
char *addr;
/* Create an anonymous mapping with all access denied */
addr = mmap(NULL, LEN, PROT_NONE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
errExit(
"mmap");
/* Display line from /proc/self/maps corresponding to mapping */
printf(
"Before mprotect()\n");
snprintf(cmd, CMD_SIZE, SHELL_FMT, (
long) getpid());
system(cmd);
/* Change protection on memory to allow read and write access */
if (mprotect(addr, LEN/8, PROT_READ) == -1)
errExit("mprotect");
if (mprotect(addr+LEN*1/8, LEN/8, PROT_WRITE) == -1)
errExit("mprotect");
if (mprotect(addr+LEN*2/8, LEN/8, PROT_EXEC) == -1)
errExit("mprotect");
if (mprotect(addr+LEN*3/8, LEN/8, PROT_READ | PROT_WRITE) == -1)
errExit("mprotect");
if (mprotect(addr+LEN*4/8, LEN/8, PROT_READ | PROT_EXEC) == -1)
errExit("mprotect");
if (mprotect(addr+LEN*5/8, LEN/8, PROT_EXEC | PROT_WRITE) == -1)
errExit("mprotect");
if (mprotect(addr+LEN*6/8, LEN/8, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
errExit("mprotect");
if (mprotect(addr+LEN*6/8, LEN/8, PROT_NONE) == -1)
errExit("mprotect"
);
printf(
"After mprotect()\n");
system(cmd);
/* Review protection via /proc/self/maps */
exit(EXIT_SUCCESS);
}

执行结果:

Before mprotect()
7f9c7225d000
-7f9c7235d000 ---s 00000000 00:05 11352269 /dev/zero (deleted)
After mprotect()
7f9c7225d000
-7f9c7227d000 r--s 00000000 00:05 11352269 /dev/zero (deleted)
7f9c7227d000
-7f9c7229d000 -w-s 00020000 00:05 11352269 /dev/zero (deleted)
7f9c7229d000
-7f9c722bd000 --xs 00040000 00:05 11352269 /dev/zero (deleted)
7f9c722bd000
-7f9c722dd000 rw-s 00060000 00:05 11352269 /dev/zero (deleted)
7f9c722dd000
-7f9c722fd000 r-xs 00080000 00:05 11352269 /dev/zero (deleted)
7f9c722fd000
-7f9c7231d000 -wxs 000a0000 00:05 11352269 /dev/zero (deleted)
7f9c7231d000
-7f9c7235d000 ---s 000c0000 00:05 11352269 /dev/zero (deleted)
2. 内存锁:mlock()和mlockall()

将进程中虚拟内存部分或者全部锁进内存以确保他们总是位于物理内存中,有两个用途:一是提高性能,对被锁住的虚拟内存提前分配了对应物理内存,不会使用时发生缺页故障而发生延迟。而是安全,敏感数据的内存分区永远不会被交换出去。

给内存加锁有如下限制:



  • 特权进程能够锁住的内存数量是没有限制的,即RLIMIT_MEMLOCK会被忽略。

  • 非特权进程能够锁住的内存数量上限由软限制RLIMIT_MEMLOCK定义。

RLIMIT_MEMLOCK限制影响:



  • mlock()和mlockall()

  • mmap() MAP_LOCKED标记,该标记用来映射被创建时将内存映射锁进内存。

  • shmctl() SHM_LOCK操作,该操作用来给System V共享内存加锁。

对mlock()、mlockall()、mmap() MAP_LOCKED操作来讲,RLIMIT_MEMLOCK定义了一个进程级别的限制,它限制了一个进程的虚拟地址空间中能够被锁进内存的字节数。

对于shmctl() SHM_LOCK操作来讲,RLIMIT_MEMLOCK定义了一个用户级别的限制,它限制了这个进程的真实用户ID在共享内存段中能够锁住的字节数。

#include
int mlock(void *addr, size_t length);
int munlock(void *addr, size_t length);
Both
return 0 on success, or –1 on error

mlock()系统调用会锁住调用进程的虚拟地址空间中add开始长度为length字节区域中所有分页。addr无需分页对齐:内核会从addr下面的下一个分页边界开始锁住分页。

mlock()调用成功之后就能确保指定区域中的分页会被锁住并驻留在物理内存中。

munlock()系统调用执行与mlock()相反。

除了显式地使用munlock()之外,内存锁在下列情况下会被自动删除:



  • 在进程终止时。

  • 当被锁住的分页通过munmap()被解除映射时。

  • 当被锁住的分页被使用mmap() MAP_FIXED标记的映射覆盖时。

#include
int mlockall(int flags);
int munlockall(void);
Both
return 0 on success, or –1 on error

mlockall()和munlockall()给它占据的所有内存加锁和解锁。

MCL_CURRENT:将调用进程的虚拟地址空间中当前所有映射的分页锁进内存,包括当前为程序文本段、数据段、内存映射以及栈分配的所有分页。

MCL_FUTURE:将后续映射进调用进程的虚拟地址空间的所有分页锁进内存。


3. 确定内存驻留性:mincore()

 mincore()是内存加锁系统调用的补充,它报告在一个虚拟地址范围中哪些分页当前驻留在RAM中,因此在访问这些分页时也不会导致分页故障。

#define _BSD_SOURCE /* Or: #define _SVID_SOURCE */
#include

int mincore(void *addr, size_t length, unsigned char *vec);
Returns
0 on success, or –1 on error
4. 建议后续的内存使用模式:madvise()

madvise()通过通知内核调用进程对起始地址为addr长度为length字节的范围之内分页的可能使用情况来提升应用程序的性能。

内核可能会使用这种信息来提升在分页之下的文件映射上执行的IO效率。

#define _BSD_SOURCE
#include

int madvise(void *addr, size_t length, int advice);
Returns
0 on success, or –1 on error

MADV_NORMAL:默认行为。

MADV_RANDOM:这个区域中的分页会被随机访问,这样预先读将不会带来任何好处,因此内核在每次读取时所取出的数据量应该尽可能少。

MADV_SEQUWNTIAL:这个范围内分页只会被方位词,并且是顺序访问,因此内核可以激进地预先读,并且分页在被访问之后就可以将其释放了。

MADV_WILLNEDD:预先读取这个区域中的分页以备将来的访问之需。

MADV_DONTNEED:调用进程不再要求这个区域中的分页主流在内存中。


5. 小结

mprotect()修改一块虚拟内存区域上的保护。

mlock()和mlockall()将一个进程的虚拟地址空间中的部分或全部分别锁进物理内存。

mincore()报告一块虚拟内存区域中哪些分页当前驻留在物理内存中。

madvise()和posix_madvise()允许一个进程将其预期的内存使用模式报告给内核。

联系方式:arnoldlu@qq.com



推荐阅读
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
author-avatar
雪莲2007019
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有