linux内存管理之sys_brk实现分析【一】 .

2023-10-24 23:48

本文主要是介绍linux内存管理之sys_brk实现分析【一】 .,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

linux struct 数据结构 file 代码分析 tree

目录(?)[+]

  1. 概述
    1. 报告题目
  2. 系统调用功能概述
  3. 数据结构分析
    1. 数据结构
    2. vm_area_struct结构体
    3. mm_struct结构体

 Linux内存管理分析报告

分析内容: linux 内存管理之sys_brk 实现分析

 

目 录

1       概述... 2

1.1       报告题目... 2

2       系统调用功能概述... 2

3       数据结构分析... 4

3.1       数据结构... 5

3.2       vm_area_struct结构体... 6

3.3       mm_struct结构体... 8

4       sbrk()系统调用代码分析... 10

4.1       用户空间的收缩... 12

4.1.1        do_munmap. 12

4.2       用户空间的伸展... 28

4.2.1        find_vma_intersection. 28

4.2.2        do_brk. 29

4.3       流程图... 34

4.4       新旧版本对比分析... 35

5       心得体会... 37

6       附录... 39

6.1       参考文献... 39

6.2       相关工具... 39

 

 

1       概述

 

1.1   报告题目

linux 内存管理之sys_brk 实现分析:系统调用brk()的流程,涉及到的主要数据结构,代码分析结果,并画出流程图来表示相关函数之间的相互调用关系。

 

2       系统调用功能概述

brk和sbrk主要的工作是实现虚拟内存到内存的映射。系统调用sbrk用来调整数据段的上限。进程的brk值是一个位于进程堆空间和它的转折点。Linux进程空间中,1--3G是用户空间,4G则是内核的。用户只能访问用户空间,内核也只能访问内核空间,它们受到MMU的严格控制。如果内核要访问用户空间,也只能通过put_user和get_user这两个宏或类似的宏才可以。

内存分配是这样的:每个进程可访问的虚拟内存空间为3G,但在程序编译时,不可能也没必要为程序分配这么大的空间,只分配并不大的数据段空间,程序中动态分配的空间就是从这一块分配的。如果这块空间不够,malloc函数族(realloc,calloc等)就调用sbrk函数将数据段的下界移动,sbrk函数在内核的管理下将虚拟地址空间映射到内存,供malloc函数使用。(参见linux内核情景分析)。

在Linux系统上,程序被载入内存时,内核为用户进程地址空间建立了代码段、数据段和堆栈段,在数据段与堆栈段之间的空闲区域用于动态内存分配。

下图简要描述了进程内存区域的分布:

下图反映了进程地址空间的管理模型:

进程的地址空间对应的描述结构是 “内存描述符结构”,它表示进程的全部地址空间,——包含了和进程地址空间有关的全部信息,其中当然包含进程的内存区域。

数据段中包括了所有静态分配的数据空间,包括全局变量和说明为static的局部变量。这些空间是进程所必须的基本要求,所以内核在建立一个进程的余兴映象时就分配好这些空间,包括虚存地址区间和页面,并建立好二者间的映射。除此之外,堆栈使用的空间也属于基本要求,所以也是在建立进程时就分配好的。所不同的是,堆栈空间安置在虚存空间的顶部,运行时由顶向下延伸;代码段和数据段则在底部,在运行时并不向上伸展。而从数据段的顶部end_data到堆栈段地址的下咽这个中间区域则是一个巨大的空洞,这就是可以在余兴时动态分配的空间。最初,这个动态分配空间是从进程的end_data开始的,这个地址为内核和进程所共知。以后,每次动态分配一块“内存”,这个边界就往上推进一段距离,同时内核和进程都要记下当前的边界在哪里。在进程这一边由malloc()或类似的库函数管理,而在内核中则将当前的边界记录在进程的mm_struct结构中。具体的说,mm_struct结构中有一个成分brk,表示动态分配区当前的底部。当一个进程需要分配内存时,将要求的大小与其当前的动态分配区底部边界相加,所得的就是所要求的新边界,也就是sbrk()调用时的参数brk。当内核能满足要求时,系统调用sbrk()返回0,此后新旧两个边界之间的虚存地址就都可以使用了。当内核发现无法满足要求(例如无力空间已经分配完),或者发现新的边界已经过于逼近设于等部的堆栈时,就拒绝分配而返回-1。

 

3       数据结构分析

一个进程的虚拟地址空间主要由两个数据结来描述。一个是最高层次的:mm_struct,一个是较高层次的:vm_area_structs。最高层次的mm_struct结构描述了一个进程的整个虚拟地址空间。较高层次的结构vm_area_truct描述了虚拟地址空间的一个区间(简称虚拟区)。它们都定义在include\linux\mm_types.h 文件中。

内核数据结构mm_struct中的成员变量start_code和end_code是进程代码段的起始和终止地址,start_data和 end_data是进程数据段的起始和终止地址,start_stack是进程堆栈段起始地址,start_brk是进程动态内存分配起始地址(堆的起始地址),还有一个 brk(堆的当前最后地址),就是动态内存分配当前的终止地址。

 

3.1   数据结构

在 Linux 内核中对应进程内存区域的数据结构是:vm_area_struct, 内核将每个内存区域作为一个单独的内存对象管理,相应的操作也都一致。采用面向对象方法使 VMA 结构体可以代表多种类型的内存区域--比如内存映射文件或进程的用户空间栈等,对这些区域的操作也都不尽相同。

vm_area_strcut 结构比较复杂,vm_area_struct 是描述进程地址空间的基本管理单元, 它是以链表形式链接,不过为了方便查找,内核又以红黑树(以前的内核使用平衡树)的形式组织内存区域,以便降低搜索耗时。并存两种组织形式,并非冗余:链表用于需要遍历全部节点的时候用,而红黑树适用于在地址空间中定位特定内存区域的时候。内核为了内存区域上的各种不同操作都能获得高性能,所以同时使用了这两种数据结构。

 

 

3.2   vm_area_struct结构体

在这个结构中,vm_start和vm_end记录了这个进程当前使用的虚拟地址空间。假设一个进程的某段合法的起始虚拟地址为A,大小为2个物理页面,就需要一个vm_area_struct来描述这段虚拟地址区域。一个进程有多个虚拟地址区域,这些vm_area_struct根据虚拟地址被组织成一颗红黑树,这主要是为了加速查找的速度。

结构体原型如下:

 

[cpp] view plain copy print ?
  1. /* 
  2.  
  3.  * This struct defines a memory VMM memory area. There is one of these 
  4.  
  5.  * per VM-area/task.  A VM area is any part of the process virtual memory 
  6.  
  7.  * space that has a special rule for the page-fault handlers (ie a shared 
  8.  
  9.  * library, the executable area etc). 
  10.  
  11.  */  
  12.   
  13. struct vm_area_struct {  
  14.   
  15.        struct mm_struct * vm_mm;       /* 指针指向进程的mm_struct结构体 */  
  16.   
  17.        unsigned long vm_start;            /* 虚拟区域的开始地址 */  
  18.   
  19.        unsigned long vm_end;            /* 虚拟区域的终止地址*/  
  20.   
  21.    
  22.   
  23.        /* 构成线性链表的指针,按虚存区基址从小到大排列*/  
  24.   
  25.        struct vm_area_struct *vm_next, *vm_prev;  
  26.   
  27.    
  28.   
  29.        pgprot_t vm_page_prot;           /*虚存区域的页面的保护特性,存取权限*/  
  30.   
  31.        unsigned long vm_flags;           /*虚拟区间的标志*/  
  32.   
  33.    
  34.   
  35.        struct rb_node vm_rb;        /*指向red_black树*/  
  36.   
  37.    
  38.   
  39.        /* 
  40.  
  41.         * For areas with an address space and backing store, 
  42.  
  43.         * linkage into the address_space->i_mmap prio tree, or 
  44.  
  45.         * linkage to the list of like vmas hanging off its node, or 
  46.  
  47.         * linkage of vma in the address_space->i_mmap_nonlinear list. 
  48.  
  49.         */  
  50.   
  51.        union { /* 或者是关联于address_space->i_mmap字段,或者是关联于i_mmap_nonlinear字段 */  
  52.   
  53.               struct {  
  54.   
  55.                      struct list_head list;  
  56.   
  57.                      void *parent; /* aligns with prio_tree_node parent */  
  58.   
  59.                      struct vm_area_struct *head;  
  60.   
  61.               } vm_set;  
  62.   
  63.    
  64.   
  65.               struct raw_prio_tree_node prio_tree_node;  
  66.   
  67.        } shared;  
  68.   
  69.    
  70.   
  71.        /* 
  72.  
  73.         * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma 
  74.  
  75.         * list, after a COW of one of the file pages.  A MAP_SHARED vma 
  76.  
  77.         * can only be in the i_mmap tree.  An anonymous MAP_PRIVATE, stack 
  78.  
  79.         * or brk vma (with NULL file) can only be in an anon_vma list. 
  80.  
  81.         */  
  82.   
  83.        struct list_head anon_vma_chain; /* Serialized by mmap_sem & 
  84.  
  85.                                      * page_table_lock */  
  86.   
  87.        struct anon_vma *anon_vma;    /* 匿名的VMA对象 */  
  88.   
  89.    
  90.   
  91.        /* Function pointers to deal with this struct. */  
  92.   
  93.        const struct vm_operations_struct *vm_ops;  /* 相关的操作表 */  
  94.   
  95.    
  96.   
  97.        /* Information about our backing store: */  
  98.   
  99.        unsigned long vm_pgoff;          /* Offset (within vm_file) in PAGE_SIZE 
  100.  
  101.                                       units, *not* PAGE_CACHE_SIZE 映射的文件vm_file的页偏移量*/   
  102.   
  103.        struct file * vm_file;            /* File we map to (can be NULL). 映射的文件指针*/  
  104.   
  105.        void * vm_private_data;             /* 私有数据 */  
  106.   
  107.        unsigned long vm_truncate_count;/* truncate_count or restart_addr */  
  108.   
  109.    
  110.   
  111. #ifndef CONFIG_MMU   
  112.   
  113.        struct vm_region *vm_region;   /* NOMMU mapping region */  
  114.   
  115. #endif   
  116.   
  117. #ifdef CONFIG_NUMA   
  118.   
  119.        struct mempolicy *vm_policy;    /* NUMA policy for the VMA */  
  120.   
  121. #endif   
  122.   
  123. };  
/*
* This struct defines a memory VMM memory area. There is one of these
* per VM-area/task.  A VM area is any part of the process virtual memory
* space that has a special rule for the page-fault handlers (ie a shared
* library, the executable area etc).
*/
struct vm_area_struct {
struct mm_struct * vm_mm;       /* 指针指向进程的mm_struct结构体 */
unsigned long vm_start;            /* 虚拟区域的开始地址 */
unsigned long vm_end;            /* 虚拟区域的终止地址*/
/* 构成线性链表的指针,按虚存区基址从小到大排列*/
struct vm_area_struct *vm_next, *vm_prev;
pgprot_t vm_page_prot;           /*虚存区域的页面的保护特性,存取权限*/
unsigned long vm_flags;           /*虚拟区间的标志*/
struct rb_node vm_rb;        /*指向red_black树*/
/*
* 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 { /* 或者是关联于address_space->i_mmap字段,或者是关联于i_mmap_nonlinear字段 */
struct {
struct list_head list;
void *parent; /* aligns with prio_tree_node parent */
struct vm_area_struct *head;
} vm_set;
struct raw_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_chain; /* Serialized by mmap_sem &
* page_table_lock */
struct anon_vma *anon_vma;    /* 匿名的VMA对象 */
/* Function pointers to deal with this struct. */
const 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 映射的文件vm_file的页偏移量*/ 
struct file * vm_file;            /* File we map to (can be NULL). 映射的文件指针*/
void * vm_private_data;             /* 私有数据 */
unsigned long vm_truncate_count;/* truncate_count or restart_addr */
#ifndef CONFIG_MMU
struct vm_region *vm_region;   /* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
struct mempolicy *vm_policy;    /* NUMA policy for the VMA */
#endif
};

 

3.3   mm_struct结构体

结构体原型如下:

 

[cpp] view plain copy print ?
  1. struct mm_struct {  
  2.   
  3.        struct vm_area_struct * mmap;         /* 指向虚拟区间(VMA)链表  */  
  4.   
  5.        struct rb_root mm_rb;                      /*指向red_black树*/  
  6.   
  7.        struct vm_area_struct * mmap_cache;     /* 最后使用内存区域 */  
  8.   
  9. #ifdef CONFIG_MMU   
  10.   
  11.        unsigned long (*get_unmapped_area) (struct file *filp,  
  12.   
  13.                             unsigned long addr, unsigned long len,  
  14.   
  15.                             unsigned long pgoff, unsigned long flags);  
  16.   
  17.        void (*unmap_area) (struct mm_struct *mm, unsigned long addr);  
  18.   
  19. #endif   
  20.   
  21.        unsigned long mmap_base;             /* base of mmap area */  
  22.   
  23.        unsigned long task_size;          /* size of task vm space */  
  24.   
  25.        unsigned long cached_hole_size;   /* if non-zero, the largest hole below free_area_cache */  
  26.   
  27.        unsigned long free_area_cache;            /* first hole of size cached_hole_size or larger */  
  28.   
  29.        pgd_t * pgd;                              /* 页全局目录 */  
  30.   
  31.        atomic_t mm_users;                  /* 该地址空间用户 */  
  32.   
  33.        atomic_t mm_count;                  /* 主使用记数 */  
  34.   
  35.        int map_count;                          /* 内存区域数目 */  
  36.   
  37.        struct rw_semaphore mmap_sem;  /* 内存区域信号量 */  
  38.   
  39.        spinlock_t page_table_lock;             /* 页表锁 */  
  40.   
  41.    
  42.   
  43.        struct list_head mmlist;              /*包含全部mm_structs的链表/ 
  44.  
  45.   
  46.  
  47.        unsigned long hiwater_rss;       /* High-watermark of RSS usage */  
  48.   
  49.        unsigned long hiwater_vm;       /* High-water virtual memory usage */  
  50.   
  51.    
  52.   
  53.        unsigned long total_vm, locked_vm, shared_vm, exec_vm;  
  54.   
  55.        unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;  
  56.   
  57.        unsigned long start_code, end_code, start_data, end_data;  /* 代码段开始地址 ,数据段首地址 */  
  58.   
  59.        unsigned long start_brk, brk, start_stack;      /* 堆首地址 堆尾地址 进程栈的首地址*/                
  60.   
  61.        unsigned long arg_start, arg_end, env_start, env_end;  /* 命令行参数的首地址 环境变量首地址 */  
  62.   
  63.    
  64.   
  65.        unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */  
  66.   
  67.    
  68.   
  69.        /* 
  70.  
  71.         * Special counters, in some configurations protected by the 
  72.  
  73.         * page_table_lock, in other configurations by being atomic. 
  74.  
  75.         */  
  76.   
  77.        struct mm_rss_stat rss_stat;  
  78.   
  79.    
  80.   
  81.        struct linux_binfmt *binfmt;  
  82.   
  83.    
  84.   
  85.        cpumask_t cpu_vm_mask;   /* 懒惰(lazy)TLB交换掩码 */  
  86.   
  87.    
  88.   
  89.        /* Architecture-specific MM context */  
  90.   
  91.        mm_context_t context;   /* 体系结构特殊数据 */  
  92.   
  93.    
  94.   
  95.        /* Swap token stuff */  
  96.   
  97.        /* 
  98.  
  99.         * Last value of global fault stamp as seen by this process. 
  100.  
  101.         * In other words, this value gives an indication of how long 
  102.  
  103.         * it has been since this task got the token. 
  104.  
  105.         * Look at mm/thrash.c 
  106.  
  107.         */  
  108.   
  109.        unsigned int faultstamp;  
  110.   
  111.        unsigned int token_priority;  
  112.   
  113.        unsigned int last_interval;  
  114.   
  115.    
  116.   
  117.        unsigned long flags; /* Must use atomic bitops to access the bits */  
  118.   
  119.    
  120.   
  121.        struct core_state *core_state; /* core开始完成 core结束完成*/  
  122.   
  123. #ifdef CONFIG_AIO   
  124.   
  125.        spinlock_t            ioctx_lock;  /* AIO I/O链表锁 */  
  126.   
  127.        struct hlist_head  ioctx_list;  /* AIO I/O链表*/  
  128.   
  129. #endif   
  130.   
  131. #ifdef CONFIG_MM_OWNER   
  132.   
  133.        /* 
  134.  
  135.         * "owner" points to a task that is regarded as the canonical 
  136.  
  137.         * user/owner of this mm. All of the following must be true in 
  138.  
  139.         * order for it to be changed: 
  140.  
  141.         * 
  142.  
  143.         * current == mm->owner 
  144.  
  145.         * current->mm != mm 
  146.  
  147.         * new_owner->mm == mm 
  148.  
  149.         * new_owner->alloc_lock is held 
  150.  
  151.         */  
  152.   
  153.        struct task_struct *owner;  
  154.   
  155. #endif   
  156.   
  157.    
  158.   
  159. #ifdef CONFIG_PROC_FS   
  160.   
  161.        /* store ref to file /proc/<pid>/exe symlink points to */  
  162.   
  163.        struct file *exe_file;  
  164.   
  165.        unsigned long num_exe_file_vmas;  
  166.   
  167. #endif   
  168.   
  169. #ifdef CONFIG_MMU_NOTIFIER   
  170.   
  171.        struct mmu_notifier_mm *mmu_notifier_mm;  
  172.   
  173. #endif   
  174.   
  175. };  

这篇关于linux内存管理之sys_brk实现分析【一】 .的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/278578

相关文章

NameNode内存生产配置

Hadoop2.x 系列,配置 NameNode 内存 NameNode 内存默认 2000m ,如果服务器内存 4G , NameNode 内存可以配置 3g 。在 hadoop-env.sh 文件中配置如下。 HADOOP_NAMENODE_OPTS=-Xmx3072m Hadoop3.x 系列,配置 Nam

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor