引言:现代操作系统提供了一种对内存的抽象概念,叫做虚拟存储器,它为每个进程提供了一个大的,一致的,和私有的地址空间。通过一个很清晰的机制,虚拟存储器提供了3个重要的能力:

1)它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,它高效的使用了主存。

2)它为每个进程提供了一致的地址空间,从而简化了存储器管理。

3)它保护了每个进程的地址空间不被其他进程破坏。

Linux操作系统同样也采用了虚拟内存技术,对一个进程而言,它好像可以访问整个系统的所有物理内存,更重要的是,即使单独一个进程,它拥有的地址空间也可以远远大于系统物理内存。

 

一:Linux虚拟内存区域及地址空间

       进程地址空间由进程可寻址的虚拟内存组成,对于某个虚拟内存地址,它要在地址空间范围内,例如: 0421f000,这个值表示的是进程32位地址空间中的一个特定的字节。尽管一个进程可以寻址4GB的虚拟内存(在32位的地址空间中),但是这并不代表它有权访问所有的虚拟地址。在地址空间中,我们更常用或者关心的是某个虚拟内存地址空间,比如 0848000-084c000,它们可以被进程访问。我们称这些可被访问的合法地址空间称为虚拟内存区域。通过内核,进程可以给自己的地址空间动态的增加或减少虚拟内存区域。

       Linux进程的虚拟内存区域一般有:代码段、数据段、堆、用户栈、共享段。每个存在的虚拟页面都保存在某个区域中,而不属于某个区域的虚拟页是不存在的,并且不能被进程访问。内核不用记录那些不存在的虚拟页,而这样的页也不占用存储器、磁盘或者内核本身的其他任何资源。

       进程只能访问有效内存区域的内存地址,每个内存区域也具有相关权限,如可读、可写、可执行性质。如果一个进程访问了无效范围中的内存区域或者以不正确的方式访问了有效地址,那么内核就会终止该进程,并返回  “段错误”信息。

     

二:内存描述符

    task_struct 中的一个条目 mm 指向mm_struct 即内存描述符,它描述了进程的虚拟内存当前状态。mm_struct 定义在linux/sched.h中:

 struct mm_struct {
struct vm_area_struct * mmap; /* list of VMAs */
struct rb_root mm_rb;
struct vm_area_struct * mmap_cache; /* last find_vma result */
unsigned long free_area_cache; /* first hole */
pgd_t * pgd;
atomic_t mm_users; /* How many users with user space? */
atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */
int map_count; /* number of VMAs */
struct rw_semaphore mmap_sem;
spinlock_t page_table_lock; /* Protects task page tables and mm->rss */ struct list_head mmlist; /* List of all active mm's. These are globally strung
* together off init_mm.mmlist, and are protected
* by mmlist_lock
*/ unsigned long start_code, end_code, start_data, end_data;
unsigned long start_brk, brk, start_stack;
unsigned long arg_start, arg_end, env_start, env_end;
unsigned long rss, total_vm, locked_vm;
unsigned long def_flags; unsigned long saved_auxv[]; /* for /proc/PID/auxv */ unsigned dumpable:;
cpumask_t cpu_vm_mask; /* Architecture-specific MM context */
mm_context_t context; /* coredumping support */
int core_waiters;
struct completion *core_startup_done, core_done; /* aio bits */
rwlock_t ioctx_list_lock;
struct kioctx *ioctx_list; struct kioctx default_kioctx;
};
这里我们主要看3个字段:1:struct vm_area_struct * mmap;  2:struct rb_root mm_rb  3: pgd_t * pgd;
    其中 pgd 指向第一级页表即页全局目录的基址,当内核运行这个进程时,它就将pgd存放在CR3寄存器内,根据它来进行地址转换工作。
    mmap 和 mm_rb 这两个不同数据结构体描述的对象是相同的:该地址空间中的所有内存区域。
    mmap 指向一个 vm_area_struct 结构的链表,利于简单、高效地遍历所有元素。
    mm_rb 指向的是一个红-黑树结构节点,适合搜索指定元素。
   
    其中每个 vm_area_struct 描述了当前虚拟地址空间的一个内存区域。这个结构定义在 文件 linux/mm.h中,如下所示:
 struct vm_area_struct {
struct mm_struct * vm_mm; /* The address space we belong to. */
unsigned long vm_start; /* Our start address within vm_mm. */
unsigned long vm_end; /* The first byte after our end address
within vm_mm. */ /* linked list of VM areas per task, sorted by address */
struct vm_area_struct *vm_next; pgprot_t vm_page_prot; /* Access permissions of this VMA. */
unsigned long vm_flags; /* Flags, listed below. */ struct rb_node vm_rb; /*
* For areas with an address space and backing store,
* linkage into the address_space->i_mmap prio tree, or
* linkage to the list of like vmas hanging off its node, or
* linkage of vma in the address_space->i_mmap_nonlinear list.
*/
union {
struct {
struct list_head list;
void *parent; /* aligns with prio_tree_node parent */
struct vm_area_struct *head;
} vm_set; struct prio_tree_node prio_tree_node;
} shared; /*
* A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
* list, after a COW of one of the file pages. A MAP_SHARED vma
* can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack
* or brk vma (with NULL file) can only be in an anon_vma list.
*/
struct list_head anon_vma_node; /* Serialized by anon_vma->lock */
struct anon_vma *anon_vma; /* Serialized by page_table_lock */ /* Function pointers to deal with this struct. */
struct vm_operations_struct * vm_ops; /* Information about our backing store: */
unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE
units, *not* PAGE_CACHE_SIZE */
struct file * vm_file; /* File we map to (can be NULL). */
void * vm_private_data; /* was vm_pte (shared mem) */ #ifdef CONFIG_NUMA
struct mempolicy *vm_policy; /* NUMA policy for the VMA */
#endif
};

 每个内存区域描述符都对应于进程地址空间中的唯一地址空间:

 vm_start 域:指向区域的首地址(最低地址),它本身在区间内。

 vm_end 域:指向区域的尾地址(最高地址)之后的第一个字节,它本身在区间外。

 vm_end - vm_start 的大小就是这个内存区域的长度,另外注意,在同一个地址空间内的不同内存区域不能重叠。

 vm_next : 指向链表中下一个区域结构。

 vm_flags:描述这个区域内的页面是共享的还是私有的。

 vm_page_prot : 描述这个区域内包含的所有页的读写许可权限。

 

三:实际使用中的内存区域

下面我们分别用/proc 文件系统和 pmap工具查看下给定进程的内存空间及所包含的内存区域。

hello.c

1 #include<stdio.h>
int main()
{ printf("Hello\n");
return ;
}

下面列出该进程地址空间中的内存区域:

先通过/proc文件系统查看:

每行数据格式为:

起始地址     -     尾部地址 访问权限    偏移      主设备号:次设备号 i节点   文件名

下面是用pmap工具查看的结果:

 

 

 

从上面可以看出:

1:可执行对象hello的 代码段、数据段 、bss段的虚拟内存区间

2:C库中libc.so的代码段、数据段、bss段

3:动态链接程序ld.so的代码段、数据段、bss段

4:分配的内存段即相当于堆段   [anon] ,分配的栈段 [stack]

5:  mappded: 2004K 表示该进程的全部地址空间大约为2004K

6:writeable/private 172k  表示可读写的内存空间大小,即消耗的物理内存空间大小。

进程访问了2003KB的数据和代码空间,而仅仅消耗了172KB的物理内存,如果一片内存区域是共享的或者不可写的,那么内核只需要在内存中为此保留一份映射。可以看出利用这种共享不可写内存的方法节约了大量内存空间。

linux内核--进程地址空间(一)的更多相关文章

  1. linux内核--进程地址空间(三)

    引言:上篇博文中,我们简单的介绍了Linux虚拟存储器的概念及组成情况,下面来分析分析进程的创建和终结及跟进程地址空间的联系. 这里首先介绍一个比较重要的概念:存储器映射 在Linux系统中,通过将一 ...

  2. Linux计算机进程地址空间与内核装载ELF

    本文基于Linux™系统对进程创建与加载进行分析,文中实现了Linux库函数fork.exec,剖析内核态执行过程,并进一步展示进程创建过程中进程控制块字段变化信息及ELF文件加载过程. 一.初识Li ...

  3. linux内核--进程与线程

    http://blog.csdn.net/yusiguyuan/article/details/12154823 在<linux内核设计与实现>中第三章讲解了进程管理,在关于进程和线程的概 ...

  4. linux内核--进程空间(二)

        内核处理管理本身的内存外,还必须管理用户空间进程的内存.我们称这个内存为进程地址空间,也就是系统中每个用户空间进程所看到的内存.linux操作系统采用虚拟内存技术,因此,系统中的所有进程之间虚 ...

  5. Linux内核——进程管理与调度

    进程的管理与调度 进程管理 进程描写叙述符及任务结构 进程存放在叫做任务队列(tasklist)的双向循环链表中.链表中的每一项包括一个详细进程的全部信息,类型为task_struct,称为进程描写叙 ...

  6. 深入理解linux内核-进程和程序

    进程描述符task_struct task_struct { //进程基本信息 pid 进程id号 tgid 线程组id号,与线程组领头线程pid号相同   getpid()返回该值 tasks in ...

  7. linux内核 进程管理

    进程和线程 进程不单单包含可执行代码(代码段),好包含打开的文件,挂起的信号,处理器状态,虚拟内存地址等. 线程:从内核的角度来说,它并没有线程这个概念.Linux把所有线程都当做进程来实现.内核并没 ...

  8. Linux内核 ——进程管理之进程诞生(基于版本4.x)

    <奔跑吧linux内核>3.1笔记,不足之处还望大家批评指正 进程是Linux内核最基本的抽象之一,它是处于执行期的程序.它不仅局限于一段可执行代码(代码段),还包括进程需要的其他资源.在 ...

  9. Linux内核——进程管理之CFS调度器(基于版本4.x)

    <奔跑吧linux内核>3.2笔记,不足之处还望大家批评指正 建议阅读博文https://www.cnblogs.com/openix/p/3262217.html理解linux cfs调 ...

随机推荐

  1. Raphaël—JavaScript Library

    Raphaël-JavaScript Library What is it? Raphaël is a small JavaScript library that should simplify yo ...

  2. 1 游戏逻辑架构,Cocos2d-x游戏项目创建,HelloWorld项目创建,HelloWorld程序分析,(CCApplicationProtocol,CCApplication,AppDeleg

     1 游戏逻辑架构 具体介绍 A 一个导演同一时间仅仅能执行一个场景,场景其中,能够同一时候载入多个层,一个层能够可载多个精灵.层中亦能够加层. B  场景切换 sceneàaddChild(la ...

  3. apache 开启压缩功能

    apache如何开启压缩功能. 1,首先先确认是安装deflatte模块.如果未安装,可以重新编译apache添加参数--enable-deflate=shared ,或者扩展安装deflate模块, ...

  4. MVCC图示

    磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面:PostgreSQL内部结构与源代码研究索引页    回到顶级页面:PostgreSQL索引页 [作者:高健@博客园 luckyjackgao ...

  5. 百度搜索附近加盟店等基于LBS云搜索功能的实现

    一.注册百度账号,进入开发者平台 创建应用并获取ak 地址如下 http://lbsyun.baidu.com/apiconsole/key/update?app-id=7546025 ok获取到了. ...

  6. 自学HTML的几个例子

    此处不赘述HTML中不同标签的用法仅仅给出自己学习时写的一些自娱自乐的例子,具体标签用法请参考W3C(http://www.w3school.com.cn/),毕竟这个才是最靠谱的,请不要相信任何二道 ...

  7. (原)前端知识杂烩(css系列)

    更新于 20160217 1. css hack .pad{ padding:17px 0 0 17px; /* 普通写法 */ *padding:17px 0 0 17px; /* *为IE7 *+ ...

  8. win7系统64位安装oracle10g

    win7系统64位安装oracle10g 下载地址: http://download.oracle.com/otn/nt/oracle10g/10204/10204_vista_w2k8_x64_pr ...

  9. [Effective Modern C++] Item 1. Understand template type deduction - 了解模板类型推断

    条款一 了解模板类型推断 基本情况 首先定义函数模板和函数调用的形式如下,在编译期间,编译器推断T和ParamType的类型,两者基本不相同,因为ParamType常常包含const.引用等修饰符 t ...

  10. mysql三张表关联查询

    三张表,需要得到的数据是标红色部分的.sql如下: select a.uid,a.uname,a.upsw,a.urealname,a.utel,a.uremark, b.rid,b.rname,b. ...