32位下的内存地址分布

32位下的内存地址分布图如下:1g为内核空间,3g为用户空间

内核空间:内核空间表示运行在处理器最高级别的超级用户模式(supervisor mode)下的代码或数据,内核空间占用从0xC0000000到0xFFFFFFFF的1GB线性地址空间,内核线性地址空间由所有进程共享,但只有运行在内核态的进程才能访问,用户进程可以通过系统调用切换到内核态访问内核空间,进程运行在内核态时所产生的地址都属于内核空间。

用户空间:
用户空间占用从0x00000000到0xBFFFFFFF共3GB的线性地址空间,每个进程都有一个独立的3GB用户空间,所以用户空间由每个进程独有,但是内核线程没有用户空间,因为它不产生用户空间地址。另外子进程共享(继承)父进程的用户空间只是使用与父进程相同的用户线性地址到物理内存地址的映射关系,而不是共享父进程用户空间。运行在用户态和内核态的进程都可以访问用户空间。
在用户空间内内存被分为:0x08048000开始
text段-代码段
text段存放程序代码,运行前就已经确定(编译时确定),通常为只读

.rodata-只读数据段
存放一些只可以读的常量数据 比如:被const修饰的全局变量,被define宏定义的常量,和只可读的字符串常量。

.data
存放在编译阶段(而非运行时)就能确定的数据,可读可写。也就是通常所说的静态存储区,赋了初值的全局变量和赋初值的静态变量存放在这个区域,常量也存放在这个区域,static 声明的变量,不管它是全局变量也好,还是在函数之中的也好,只要是没有赋初值都存放在.bss段,如果赋了初值,则把它放在.data段。

.bss
定义而没有赋初值的全局变量和静态变量,放在这个区域;

heap
堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。
当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);
当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。由低向高。

共享库区域
这里被内核用来把文件内容直接映射到内存。所有的应用程序都可以使用linux提供的mmap()系统调用或者在windows中使用CreateFileMapping()/MapViewOfFile来进行这样的映射。memory mapping是进行文件I/O的高效方法,所以动态库的加载使用这个方式来实现。当然,也可以进行一些不关联到文件的程序数据的匿名memory mapping。在linux中,如果你通过malloc()来申请一块大的内存,C库就会在memory mapping segment中创建一个匿名memory mapping而不是使用堆空间。这里的“大”意味着大于MMAP_THRESHOLD字节,默认是128kb,可以通过mallopt()来进行调整。

stack
stack段存储参数变量和局部变量,由系统进行申请和释放,属于静态内存分配。由高向低

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
(1)假设每个页面可存放10条指令,分配给一作业的内存数为4. (2)用C语言模拟一作业的执行过程,该作业共有320条指令,即它的地址空间为32页,目前它的所有页面都还未调入内存。在模拟过程中,如果所访问的指令已在内存,则显示其物理地址,并转下一条指令。如果所访问的指令还未装入内存,则发生缺页,此时须记录缺页的次数,并将相应页调入内存;如果4个内存块中均装入该作业,则需要进行页面置换;最后显示其物理地址,并转下一条指令。在所有320条指令执行完后,请计算并显示作业运行过程中发生的缺页率。 (3)置换算法请分别考虑OPT、FIFO和LRU算法。 (4)作业中指令的访问次序按下述原则生成: 50%的指令是顺序执行的; 25%的指令是均匀分布在前地址部分; 25%的指令是均匀分布在后地址部分; 具体的实施办法是: ①在[0,319]之间随机选取一条开始执行指令,其序号为m; ②顺序执行下一条指令,即序号为m+1的指令; ③通过随机数,跳转到前地址部分[0,m-1]中的某条指令处,其序号为; ④顺序执行下一条指令,即序号为+1; ⑤通过随机数,跳转到后地址部分[+2,319]中的某条指令处,其序号为; ⑥顺序执行下一条指令,即序号为+1; ⑦重复跳转到前地址部分、顺序执行、跳转到后地址部分、顺序执行的过程,直至320条指令执行完。
06-10
为了模拟作业的执行过程,我们可以使用一个数组来保存作业的所有指令,另外再定义一个长度为4的数组来模拟内存中的页面。具体的C语言实现如下: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> #define PAGE_SIZE 10 // 页面大小 #define PAGE_NUM 32 // 页面数 #define MEM_SIZE 4 // 内存大小 int job[PAGE_SIZE * PAGE_NUM]; // 作业的所有指令 int memory[MEM_SIZE]; // 内存中的页面 int page_fault = 0; // 缺页次数 // 初始化作业指令 void init_job() { int i; for (i = 0; i < PAGE_SIZE * PAGE_NUM; i++) { job[i] = i; } } // 获取指令对应的页面号 int get_page_num(int instruction) { return instruction / PAGE_SIZE; } // 判断页面是否在内存中 int is_page_in_memory(int page_num) { int i; for (i = 0; i < MEM_SIZE; i++) { if (memory[i] == page_num) { return 1; } } return 0; } // 获取被置换页面的下标 int get_replace_index(int* used) { int i, index = 0; for (i = 1; i < MEM_SIZE; i++) { if (used[i] < used[index]) { index = i; } } return index; } // 置换页面,使用OPT算法 void replace_page_opt(int* used, int* next_use) { int i, j, max_gap = -1, index = 0; for (i = 0; i < MEM_SIZE; i++) { int gap = PAGE_SIZE; for (j = 0; j < PAGE_SIZE * PAGE_NUM; j++) { if (job[j] == memory[i]) { if (next_use[j] > i) { gap = next_use[j] - i; } break; } } if (gap > max_gap) { max_gap = gap; index = i; } } memory[index] = job[next_use[memory[index]]]; } // 置换页面,使用FIFO算法 void replace_page_fifo(int* used, int* next_use) { int index = 0, i; for (i = 1; i < MEM_SIZE; i++) { if (next_use[memory[i]] < next_use[memory[index]]) { index = i; } } memory[index] = job[next_use[memory[index]]]; } // 置换页面,使用LRU算法 void replace_page_lru(int* used, int* next_use) { int index = get_replace_index(used); memory[index] = job[next_use[memory[index]]]; } // 执行作业中的指令 void run_job() { int i, j = 0; int used[MEM_SIZE] = {0}; int next_use[PAGE_SIZE * PAGE_NUM] = {0}; for (i = 0; i < PAGE_SIZE * PAGE_NUM; i++) { next_use[i] = PAGE_SIZE * PAGE_NUM; } // 50%的指令是顺序执行的 for (i = 0; i < PAGE_SIZE * PAGE_NUM / 2; i++) { int page_num = get_page_num(job[j]); if (is_page_in_memory(page_num)) { printf("物理地址:%d\n", j % PAGE_SIZE + memory[page_num] * PAGE_SIZE); } else { printf("发生缺页\n"); page_fault++; if (j < MEM_SIZE) { memory[j] = page_num; } else { int k; for (k = 0; k < MEM_SIZE; k++) { if (!is_page_in_memory(page_num)) { memory[k] = page_num; break; } } if (k == MEM_SIZE) { // 需要进行页面置换 if (i % 3 == 0) { replace_page_opt(used, next_use); } else if (i % 3 == 1) { replace_page_fifo(used, next_use); } else { replace_page_lru(used, next_use); } } } } used[j % MEM_SIZE] = i; next_use[j] = i + 1; j++; } // 25%的指令是均匀分布在前地址部分 for (i = 0; i < PAGE_SIZE * PAGE_NUM / 4; i++) { int k = rand() % j; int page_num = get_page_num(job[k]); if (is_page_in_memory(page_num)) { printf("物理地址:%d\n", k % PAGE_SIZE + memory[page_num] * PAGE_SIZE); } else { printf("发生缺页\n"); page_fault++; if (j < MEM_SIZE) { memory[j] = page_num; } else { int k; for (k = 0; k < MEM_SIZE; k++) { if (!is_page_in_memory(page_num)) { memory[k] = page_num; break; } } if (k == MEM_SIZE) { // 需要进行页面置换 if (i % 3 == 0) { replace_page_opt(used, next_use); } else if (i % 3 == 1) { replace_page_fifo(used, next_use); } else { replace_page_lru(used, next_use); } } } } used[j % MEM_SIZE] = i; next_use[k] = i + 1; j++; } // 25%的指令是均匀分布在后地址部分 for (i = 0; i < PAGE_SIZE * PAGE_NUM / 4; i++) { int k = rand() % (PAGE_SIZE * PAGE_NUM - j) + j; int page_num = get_page_num(job[k]); if (is_page_in_memory(page_num)) { printf("物理地址:%d\n", k % PAGE_SIZE + memory[page_num] * PAGE_SIZE); } else { printf("发生缺页\n"); page_fault++; if (j < MEM_SIZE) { memory[j] = page_num; } else { int k; for (k = 0; k < MEM_SIZE; k++) { if (!is_page_in_memory(page_num)) { memory[k] = page_num; break; } } if (k == MEM_SIZE) { // 需要进行页面置换 if (i % 3 == 0) { replace_page_opt(used, next_use); } else if (i % 3 == 1) { replace_page_fifo(used, next_use); } else { replace_page_lru(used, next_use); } } } } used[j % MEM_SIZE] = i; next_use[k] = i + 1; j++; } } int main() { srand(time(NULL)); init_job(); run_job(); printf("缺页率:%f\n", (float)page_fault / (PAGE_SIZE * PAGE_NUM)); return 0; } ``` 在上面的代码中,我们使用了三种页面置换算法:OPT(最佳置换)、FIFO(先进先出)和LRU(最近最少使用)。三种算法的实现都在 `replace_page_opt`、`replace_page_fifo` 和 `replace_page_lru` 函数中。其中,`used` 数组记录了每个页面最后一次被使用的时间戳,`next_use` 数组记录了每个指令下一次被使用的时间戳,用于计算页面的使用距离。在实现过程中,我们还使用了 `rand()` 函数来随机生成跳转到前地址部分和后地址部分的指令。 最后,我们在 `main` 函数中调用 `init_job()` 和 `run_job()` 函数来执行作业,并计算缺页率。注意,缺页率的计算方法是缺页次数除以总指令数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值