虚拟存储器

我们都知道每个进程都拥有4G的线性地址空间, 3G的用户空间,1G的内核空间。但是是否存在这个4G的线性空间?如果存在,那么2个进程就拥有了8G的内存空间,与事实的不符的是只有4G的物理内存空间。则这个4G线地址空间并不是真实的存在,是对主存的抽象概念,是一种虚拟的存储器,是我们使用数据结构构造虚拟空间。虚拟存储器为每个进程提供了一致的地址空间简化了存储器的管理。也为每个进程的线性地址空间提供了保护,不被其他的进程破坏(通过权限和地址映射)。

现代操作系统使用页存储管理机制来使这个虚拟存储器进行工作的,但是如何构造每个进程的虚拟存储器?

在linux中,使用vm_area_struct结构体来构造这个4G的线性地址空间,程序在装载的时候,会尽量把相同权限属性的段分配到同一空间,进程还有多个段信息,每个段信息将由一个vm_area_struct来索引。(机器环境:fedora:3.11.10-100.fc18.x86_64,kernel:linux-3.16.3)

4G线性地址空间

struct vm_area_struct {

unsigned long vm_start;

unsigned long vm_end;

/*vm_start段的首地址,vm_end 段的尾地址

*/

struct vm_area_struct *vm_next, *vm_prev;

struct rb_node vm_rb;

/*vm_next, vm_prev是vm_area_struct的链表结构,而vm_rb 是vm_area_struct的树形结构(红黑树),链表用于遍历全部节点的时候,

*红黑树适用于地址空间中定位特定内存区域的时候,同时使用这两种数据结构,是为了在不同的操作中都能获得高性能

*/

unsigned long rb_subtree_gap;

/*Largest free memory gap in bytes to the left of this VMA.

*Either between this VMA and vma->vm_prev, or between one

*of the  VMAs below us in the VMA rbtree and its ->vm_prev.

*This helps  get_unmapped_area find a free area of the right size.

*(我的理解就是没有映射的区域(两个VMA之间的距离,但是使用内核模块打印这个值,与VMA的距离是不符的))

*/

struct mm_struct  *vm_mm;

/*与此VMA相关的mm_struct

*/

pgprot_t vm_page_prot;

/*进程访问控制权限

*/

unsigned long vm_flags;

/*VMA的标志,例如:页面可读写可执行,是否共享.....

*/

union {

struct {

struct rb_node rb;

unsigned long rb_subtree_last;

} linear;

struct list_head nonlinear;

}shared;

/*
* For areas with an address space and backing store,
* linkage into the address_space->i_mmap interval tree, or
* linkage of vma in the address_space->i_mmap_nonlinear list.

*跟高速缓存有关
*/

struct list_head anon_vma_chain;

struct anon_vma *anon_vma;

/*anon_vma_chaon是annon_vma构成的链表,anon_vma是匿名VMA对象,例如堆就是匿名映射

*/

const struct vm_operations_struct *vm_ops;

/*指定内存区域相关的操作函数表,包括open,close,fault.....

*/

unsigned long vm_pgoff;

struct file *vm_file;

void *vm_private_data;

/*vm_pgoff是在vm_file 文件中的偏移。vm_file 是被映射的文件,vm_private_data是私有数据

*/

#ifndef CONFIG_MMU

struct vm_region *vm_region

/*The vm_region function returns information on a region within the specified task's address space,but in there ,the specified address is nommu mapping region*/

#endif

#ifdef CONFIG_NUMA

struct mempolicy *vm_policy; /*VMA使用NUMA架构*/

#endif

}

怎么查看虚拟存储器,可是使用/proc/pid/maps或者pmap pid来查看进程的虚拟地址空间,当然我们也可以实现自己的kernel module来查看虚拟地址空间:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
MODULE_LICENSE("GPL");

static int __init module(void)
{

struct pid *current_pid;
struct task_struct *current_task;

struct mm_struct  *mymm;
struct vm_area_struct *pos = NULL;

current_pid = find_vpid(xxx);
current_task = pid_task(current_pid, PIDTYPE_PID);

mymm = current_task->mm;
for(pos = mymm->mmap; pos; pos = pos->vm_next) {

printk("0x%hx-0x%hx\t", pos->vm_start, pos->vm_end);

if(pos->vm_flags & VM_READ) {

printk("r");

} else {

printk("-");

}

if(pos->vm_flags & VM_WRITE) {

printk("w");

} else {

printk("-");

}

if(pos->vm_flags & VM_EXEC) {

printk("x");

} else {

printk("-");

}

printk("\n");

}

return 0;

}

static void __exit rmodule(void)
{

printk(KERN_ALERT"Goodbye,world\n");

}
module_init(module);
module_exit(rmodule);

将上面的程序保存为vm_area_struct.c,然后使用下面的Makefile文件进行编译:

obj-m := vm_area_struct.o
CURRENT_PATH := ${shell pwd}
CURRENT_KERNEL_PATH := ${shell uname -r}
LINUX_KERNEL_PATH := /usr/src/kernels/$(CURRENT_KERNEL_PATH)

all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

生成vm_area_struct.ko文件,用root权限执行 insmod vm_area_struct.ko, 然后执行lsmod 来查看kernel模块是否加载进去,然后查看/var/log/message文件查看结果,最后使用rmmod vm_area_struct卸载内核模块。

在message文件输出与maps文件对比,出现了http://stackoverflow.com/questions/26277134/about-the-proc-xx-map-and-the-vm-area-struct

在/proc/maps中不会出现栈保护页,而使用内核模块会出现这个4K的页,故会出现上述的问题。可在kernel中的./fs/proc/task_mmu.c中查看。

参考资料:

1:深入理解计算机系统 第9章,主要还是虚拟存储器的如何工作的和如何使用管理虚拟存储器;

2:linux内核设计与实现,主要是数据结构的介绍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值