嵌入式linux c 学习笔记9---虚拟内存管理

2019-07-12 15:15发布

/*
 * =====================================================================================
 *
 *       Filename:  sharelib.c
 *
 *    Description:  share lib
 *
 *        Version:  1.0
 *        Created:  2010年11月05日 09时31分24秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Yang Shao Kun (), cdutyangshaokun@163.com
 *        Company:  College of Information Engineering of CDUT
 *
 * =====================================================================================
 */

组成共享库的目标文件和一般的目标文件有不同,在编译的时候要加上-fPIC选项,
-f 后面跟一些编译选项。

va --mmu

/proc目录下的文件并不是真正的磁盘文件,而是由内核虚拟出来的,当前运行的每个
进程在/proc下都有一个子目录,目录名就是进程的id。


[yskcg@yskcg study]$ cat /proc/38
38/   382/  3843/
[yskcg@yskcg study]$ cat /proc/3843/maps
00325000-00326000 r-xp 00000000 00:00 0          [vdso]
00485000-00491000 r-xp 00000000 08:02 65436      /lib/libnss_files-2.12.1.so
00491000-00492000 r--p 0000b000 08:02 65436      /lib/libnss_files-2.12.1.so
00492000-00493000 rw-p 0000c000 08:02 65436      /lib/libnss_files-2.12.1.so
00870000-0088e000 r-xp 00000000 08:02 65326      /lib/ld-2.12.1.so
0088e000-0088f000 r--p 0001d000 08:02 65326      /lib/ld-2.12.1.so
0088f000-00890000 rw-p 0001e000 08:02 65326      /lib/ld-2.12.1.so
00892000-00a17000 r-xp 00000000 08:02 65332      /lib/libc-2.12.1.so
00a17000-00a18000 ---p 00185000 08:02 65332      /lib/libc-2.12.1.so
00a18000-00a1a000 r--p 00185000 08:02 65332      /lib/libc-2.12.1.so
00a1a000-00a1b000 rw-p 00187000 08:02 65332      /lib/libc-2.12.1.so
00a1b000-00a1e000 rw-p 00000000 00:00 0
00a20000-00a23000 r-xp 00000000 08:02 66606      /lib/libdl-2.12.1.so
00a23000-00a24000 r--p 00002000 08:02 66606      /lib/libdl-2.12.1.so
00a24000-00a25000 rw-p 00003000 08:02 66606      /lib/libdl-2.12.1.so
04172000-04190000 r-xp 00000000 08:02 66415      /lib/libtinfo.so.5.7
04190000-04193000 rw-p 0001d000 08:02 66415      /lib/libtinfo.so.5.7
08047000-08118000 r-xp 00000000 08:02 66615      /bin/bash
08118000-0811d000 rw-p 000d1000 08:02 66615      /bin/bash
0811d000-08122000 rw-p 00000000 00:00 0
09184000-091c6000 rw-p 00000000 00:00 0          [heap]
b7623000-b7823000 r--p 00000000 08:08 177248     /usr/lib/locale/locale-archive
b7823000-b7825000 rw-p 00000000 00:00 0
b783e000-b7840000 rw-p 00000000 00:00 0
b7840000-b7847000 r--s 00000000 08:08 166517     /usr/lib/gconv/gconv-modules.cache
b7847000-b7848000 rw-p 00000000 00:00 0
bfca4000-bfcc5000 rw-p 00000000 00:00 0          [stack]

我们来分析这段内存信息:

08047000-08118000 r-xp 00000000 08:02 66615      /bin/bash
08118000-0811d000 rw-p 000d1000 08:02 66615      /bin/bash

我们知道,x86平台的虚拟地址空间是0x00000000~0xffffffff,大致是前面的3Gb 0x00000000~0xbfffffff 是用户空间,后1Gb是内核空间。

08047000-0811800 是重/bin/bash文件加载到内存的,访问的权限是 rx,表示的是text segment。 0811800-0811d000 也是重/bin/bash文件加载到内存的,访问的权限是rw表示的是data segment。

09184000-091c6000 rw-p 00000000 00:00 0          [heap]
不是重磁盘文件加载到内存的,这段空间是堆,我们可以看到重堆空间结束到共享库空间有一段地址没有用,动态分配内存是堆空间可以向高地址增长,并且有很大的增长余地,堆空间的上限是b7623000,我们称为break 堆空间要向高地址增长就要抬高break,映射新的虚拟内存页面到物理地址。

00325000-00326000 r-xp 00000000 00:00 0          [vdso]
标有vsdo的地址范围是linux-gate.so.1的映射空间,这个是有内核虚拟出来的。



bfca4000-bfcc5000 rw-p 00000000 00:00 0          [stack]
这个是栈空间,用来保存变量和其他的参数,它是向低地址扩展。

虚拟内存管理机制的作用:
    1:可以控制物理内存的访问权限,物理内存本身是不限制访问的,任何地址都可以读写,而操作系统要求不同的页面具有不同的访问权限,这是利用cpu模式和mmu的内存保护机制实现的。
    2:使每个进程有独立的地址空间,不同的进程中相同的va被mmu映射到不同的pa。独立空间的好处是:
    任何一个进程由于执行了错误指令或恶意的代码而导致的非法内存访问都不会意外改写其他进程的数据,也不会影响其他进程的运行。

    3:va到pa的映射会给分配和释放内存带来方便,物理地址不连续的几块内存可以映射成虚拟地址连续的一块内存。
    4:一个系统如果同时运行着很多的进程,为各进程分配的内存之和可能会大于实际可用的物理内存,在使用虚拟内存管理机制后,进程访问的虚拟内存页面,这些页面的数据可以保存物理页面中,也可以临时保存在磁盘上而不占用物理页面,可以在磁盘上开一个分区或者建立一个文件专门用于临时保存虚拟内存页面的数据,这个称为交换设备,在启用了交换设备后,系统中可以分配的内存总量等于物理内存大小和交换设备大小之和。

    换出:当物理内存不够用时,操作系统将一些不常用的物理页面中的数据临时保存到交换设备中,同时减除va到pa的映射,这个物理页面就是可以认为是空闲的了,也可以重新分配给进程使用。
    如果进程访问到被交换的虚拟内存页面,由于va到pa的映射不存在,访问该内存的指令会引发一个异常,我们称为缺页错误。
    这时进入到异常处理程序,操作系统重新把缺失的页面充交换设备再加载回物理内存,并建立va到pa的映射,然后重新回到用户模式下重新执行那条访问内存的指令,这个我们称为  换入。
    换入和换出操作系统称为  换页。

我们重新ps一下:yskcg@yskcg study]$ ps
  PID TTY          TIME CMD
 5956 pts/2    00:00:00 bash
 5970 pts/2    00:00:00 ps

然后执行cat /proc/5956/maps

0019f000-001a0000 r-xp 00000000 00:00 0          [vdso]
004fd000-00509000 r-xp 00000000 08:02 65436      /lib/libnss_files-2.12.1.so
00509000-0050a000 r--p 0000b000 08:02 65436      /lib/libnss_files-2.12.1.so
0050a000-0050b000 rw-p 0000c000 08:02 65436      /lib/libnss_files-2.12.1.so
00870000-0088e000 r-xp 00000000 08:02 65326      /lib/ld-2.12.1.so
0088e000-0088f000 r--p 0001d000 08:02 65326      /lib/ld-2.12.1.so
0088f000-00890000 rw-p 0001e000 08:02 65326      /lib/ld-2.12.1.so
00892000-00a17000 r-xp 00000000 08:02 65332      /lib/libc-2.12.1.so
00a17000-00a18000 ---p 00185000 08:02 65332      /lib/libc-2.12.1.so
00a18000-00a1a000 r--p 00185000 08:02 65332      /lib/libc-2.12.1.so
00a1a000-00a1b000 rw-p 00187000 08:02 65332      /lib/libc-2.12.1.so
00a1b000-00a1e000 rw-p 00000000 00:00 0
00a20000-00a23000 r-xp 00000000 08:02 66606      /lib/libdl-2.12.1.so
00a23000-00a24000 r--p 00002000 08:02 66606      /lib/libdl-2.12.1.so
00a24000-00a25000 rw-p 00003000 08:02 66606      /lib/libdl-2.12.1.so
04172000-04190000 r-xp 00000000 08:02 66415      /lib/libtinfo.so.5.7
04190000-04193000 rw-p 0001d000 08:02 66415      /lib/libtinfo.so.5.7
08047000-08118000 r-xp 00000000 08:02 66615      /bin/bash
08118000-0811d000 rw-p 000d1000 08:02 66615      /bin/bash
0811d000-08122000 rw-p 00000000 00:00 0
09497000-094d9000 rw-p 00000000 00:00 0          [heap]
b758c000-b778c000 r--p 00000000 08:08 177248     /usr/lib/locale/locale-archive
b778c000-b778e000 rw-p 00000000 00:00 0
b77a7000-b77a9000 rw-p 00000000 00:00 0
b77a9000-b77b0000 r--s 00000000 08:08 166517     /usr/lib/gconv/gconv-modules.cache
b77b0000-b77b1000 rw-p 00000000 00:00 0
bf92a000-bf94b000 rw-p 00000000 00:00 0          [stack]

我们发现,在/bin/bash段的data segemnt段和刚才的进程3843的bash进程的地址段是一样的,同时相同的还有 text segemnt段,
因为两个进程都是bash,所以text segement是一样的,并且text segemnt 是只读的,不会被改写,因此操作系统安排两个相同的text segemnnt 共享同一个物理页面,
那么我们的 data segement 段的数据呢:因为我们的data segement占据的是相同的虚拟地址,然后根据内存管理机制后,映射到不同的物理地址。