linux内存管理(2)-用户空间

本文探讨了Linux内存管理中用户空间的部分,包括编译链接如何确定变量地址,用户空间进程内存的管理结构体如task_struct、mm_struct和vm_area_struct,以及malloc在用户空间的实现过程,涉及brk系统调用和内存映射。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 编译链接的一些知识

首先,我们来编写一个简单的程序,示例代码如下

#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int i=3;
int j=4;
int main()
{
   printf("value i is %d\n,address of i is 0x%lx\naddress of j is 0x%lx\n",i,(unsigned int)&i,(unsigned int )&j);
}

程序片段1

程序片段1定义了两个变量,ab,并分别赋值为34。然后在主函数main中,打印了ij的值及其对其对应的虚拟地址。程序的运行结果如下:

value i is 3
address of i is 0x80495e0,
address of j is 0x80495e4

片段1

程序片段2中所示的0x80495e00x80495e4分别是ij的虚拟地址,那么,这个地址是怎么确定的?由谁来确定?

通过查看编译后的可执行程序的符号列表,ij的地址实际上是在链接的过程中确定的,由编译器来确定。

objdump -t a.out

a.out:     file format elf32-i386

SYMBOL TABLE:
......
00000000  w      *UND*  00000000              _Jv_RegisterClasses
08048494 g     O .rodata        00000004              _fp_hw
08048478 g     F .fini  00000000              _fini
00000000       F *UND*  0000019f              __libc_start_main@@GLIBC_2.0
08048498 g     O .rodata        00000004              _IO_stdin_used
080495dc g       .data  00000000              __data_start
080495e0 g     O .data  00000004              i
0804849c g     O .rodata        00000000              .hidden __dso_handle
080494f0 g     O .dtors 00000000              .hidden __DTOR_END__
080483e0 g     F .text  00000069              __libc_csu_init
00000000       F *UND*  00000039              printf@@GLIBC_2.0
080495e8 g       *ABS*  00000000              __bss_start
080495e4 g     O .data  00000004              j
080495f0 g       *ABS*  00000000              _end
080495e8 g       *ABS*  00000000              _edata
08048449 g     F .text  00000000              .hidden __i686.get_pc_thunk.bx
08048384 g     F .text  00000044              main
08048250 g     F .init  00000000              _init

 

2. 管理用户空间进程内存的结构体

当一个程序被载入内存,内核就会为其建立一个名为task_struct的结构体来管理这个进程。

struct task_struct {
    struct list_head tasks;
    struct mm_struct *mm, *active_mm;//字段mm为该进程的内存管理。
    pid_t pid;
    struct fs_struct *fs;
    struct files_struct *files;
......
};

task_struct

struct mm_struct {
    struct vm_area_struct * mmap; /* list of VMAs ,一个进程有一个mm_struct,多个
                                vm_area_struct*/
    pgd_t * pgd;
    int map_count; /* number of VMAs */
......
};

mm_struct

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. */
}

vm_area_struct

小结:整个内存管理的体系可以这么理解,在32位系统上,所有的地址(04G),页表、页框等都统一由内核管理。而内核中的服务(这里的服务包括内运行在内核中的进程,内核变量等)只是占用了3-4G这个地址空间段。对于用户空间而言,进程的地址是由编译器决定的,编译器在链接各个库文件时,用了0-3G的地址。

对于硬件MMU模块而言,它并不关心Linux给它的地址属于哪个空间,MMU只是根据所设定的规则(内存映射表)找到对应的物理地址。

各结构体之间关系图

3. 用户空间malloc的实现

由前面的小结知道,内存管理都在内核空间进行。对于malloc申请的一块内存也是一样,先来看一下malloc调用的图示:

malloc->brk()->SYSCALL_DEFINE1(brk, unsigned long, brk)->__get_free_pages() 

SYSCALL_DEFINE1这个系统调用,将执行的状态从用户空间转向内核空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值