Linux内核笔记--内存管理之用户态进程内存分配

内核版本:linux-2.6.11


Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你这一切。

线性区

一个可执行程序,是经过编译器处理后的遵守一定规则的数据、符号表和指令序列的组合,当linux加载一个可执行程序的时候,会为其创建一个新的进程,其对应的进程描述符task_struct中会保存许多资源的描述符,其中的mm_struct就是这个进程的内存描述符,用来管理该进程拥有的所有内存。

一个进程拥有的内存是动态变化的,比如栈的扩充、堆的扩充、新的文件映射等等,出于这个原因,需要一个更细粒度的单位来实现内存的动态增加减少,这个单位叫线性地址区间,简称线性区,用vm_area_struct描述。

线性地址空间

线性地址空间是基于单个进程的,暂时抛开写时复制机制不谈,不同进程之间的线性地址空间是彼此隔离的,这是由linux的多级分页机制实现。
一个进程拥有的线性地址空间的具体表示就是这个进程的内存描述符中存储的线性区的集合。

死程序,活进程

现在,我们知道了,进程是通过增加和减少线性区来管理自己拥有的内存,并通过逻辑地址加上某一个线性区的基地址来进行寻址操作,那么ok,这两点已经能够保证一个四肢头脑健全的进程正常运行,然而,一个可执行程序是存在硬盘上的,是一个死的东西,linux加载器需要把它变成活的,需要给她四肢给她头脑,即把她的代码、数据、栈、依赖库全部放到内存中。
这个过程,从do_fork开始。

do_fork和写时复制

Linux用do_fork来创建一个新的用户态进程,写时复制机制让新的子进程在不进行写操作的前提下会拥有父进程的所有页框,相当于父子进程拥有相同的线性区,当子进程对线性区写操作或者执行exec的时候,系统会将子进程的mm_struct重新初始化,

简单说下写时复制机制的实现:主要函数调用流程do_fork-->copy_process-->copy_mm-->dup_mmap-->copy_page_range,copy_page_range将父进程的多级页表结构整个复制一遍,此时,父子进程拥有彼此分离的多级页表结构,但在最后一级页表中存放的相同的页描述符,即子进程在进行写操作之前依然跟父进程共享相同的页,当子进程对某个共享页进行写操作时,系统会将执行流定向到do_wp_page,这个函数将复制一个新的页来替换要写的页。因此一个新的进程在初始的时候跟父进程共享相同的地址空间,但经过一段时间后,父子进程的地址空间将变得真正隔离开来。

分配线性区

然而运行一个新的程序会干掉所有旧的内存空间,并为新进程重新分配新的线性地址空间,从sys_execve()即exec的系统调用例程开始,调用流程依次是sys_execve-->do_execve-->mm_alloc-->mm_init-->mm_alloc_pgd-->pgd_alloc。最后这个pgd_alloc为这个进程分配了一个新的页全局目录(第一级页表)。
此时,该进程的线性地址空间依然为空,因为还未曾为其分配任何线性区。

sys_execve()会在最后会调用这个可执行程序对应格式的load_binary函数,这个函数完成了这种格式的可执行程序的加载,其中最主要的过程就是多次调用do_mmap为该进程分配一系列的线性区并存放不同的内容,分配顺序是,栈段->代码段->数据段->bss->依赖库,堆是在运行过程中动态分配的,由内核中brk和mmap函数实现,C库将其封装成我们熟知的malloc函数。
线性区的分配简单说就是扫描用户态线性地址空间(32位系统下通常是从0x40000000开始的低3G的空间),查找一个足够大的线性地址范围。

经过以上的过程,新进程拥有了自己的线性地址空间,但是别忘了,系统从未给这个进程分配任何可用的物理页,
仅仅只初始化了一个页全局目录,那么,当进程寻址的时候,MMU如何正确进行地址转换呢。

分配页框(填充页表)

Linux顺理成章的将新进程物理页的分配放在了缺页异常处理程序中,进程运行前期会频繁通过缺页异常来请求分页,缺页异常处理程序最终会调用伙伴系统的一个入口alloc_pages来分配新的页框并为缺页的线性地址填充页表,一段时间后,该进程的运行环境就会被完全载入内存。

至此,死程序变活进程。

插一段:sys_execve()第一步是调用getname()函数,获得程序名网上和一些书上说这个函数是用来得到一个新的页框并从用户空间拷贝程序名到这个页框中,然而,2.6的源码最终指向的一个函数是kmem_cache_alloc(cachep, flags),这个函数我在Linux内核笔记——内存管理之slab分配器里提到过,这是slab分配器的调用入口,所以从这里可以知道,getname其实是通过指定一个叫names_cachep的高速缓存描述符来分配一个这个类型的内存对象,这个names_cachep则是一个kmem_cache_t类型的指针,是一种高速缓存类型,所以这里说获得一个新的页框是欠妥的,实际上getname是获得了一个names_cachep这种高速缓存里注册的构造函数对应的一个指定的可用内存对象,然后再存入程序名到这个内存对象中。虽然这个对象可能就是一个普通页框,这依赖于这个注册的构造函数,
详细解释见Linux内核笔记——内存管理之slab分配器。


PS: 个人理解,错误难免,望能指出,万分感谢

转载于:https://www.cnblogs.com/JaSonS-toy/p/4998936.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/289785.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android之javax.net.ssl.SSLPeerUnverifiedException: Hostname ip not verified:解决办法

1、问题 用HttpURLConnection去请求的时候抛了下面的异常 HttpRequest$HttpRequestException: javax.net.ssl.SSLPeerUnverifiedException: Hostname ip not verified: 2、分析和解决 从异常来看是因为SSL协议握手的过程中,这个服务度地址的证书没有被证实,被信任。 clien…

php 字符串进行计算_怎么在php中利用eval对字符串格式进行计算

怎么在php中利用eval对字符串格式进行计算发布时间:2020-12-16 16:42:57来源:亿速云阅读:101作者:Leah本篇文章给大家分享的是有关怎么在php中利用eval对字符串格式进行计算,小编觉得挺实用的,因此分享给大…

Xamarin效果第十四篇之玩耍GIS

最近再次拾起Xamarin然后也实现了祖传PLC控制和弹窗配置;这不又一次勾起来我想基于他玩玩原来一直玩耍的GIS,毕竟咱前面一直玩耍二维和三维的GIS相关的知识点;有兴趣的小伙伴可以翻翻我的历史文章;趁着激情满满;来看看最终咱实现的加载高德平面地图效果(有水印):再者就是满足群…

Android下载apk异常java.net.SocketTimeoutException: timeout解决办法

1、问题 实现下载apk的时候,抛出下面异常 java.net.SocketTimeoutException: timeout 2、分析 很明显是socket超时了,由于我的wifi网络比较慢,设置的超时时间可能短了。 在写入由 GetRequestStream 方法返回的流时,或在读取由…

SQL SERVER两种分页的存储过程介绍

由于现在很多的企业招聘的笔试都会让来招聘的写一个分页的存储过程,有的企业甚至要求应聘者用两种方式实现分页,如果没有在实际项目中使用过分页,那么很多的应聘者都会出现一定的问题,下面介绍两种分页的方法。 一、 以学生表为例,在数据库中有一个Student表,字段有 …

Java Socke 探究

Java中的Socket可以分为普通Socket和NioSocket两种。 普通Socket的用法 Java中的网络通信是通过Socket实现的,Socket分为ServerSocket和Socket两大类,ServerSocket用于服务端,可以通过accept方法监听请求,监听到请求后返回Socket&…

codeforces 600D Area of Two Circles' Intersection

分相离,内含,想交三种情况讨论一下。 主要是精度和数据范围的问题,首先数据用long double,能用整型判断就不要用浮点型。 题目中所给的坐标,半径是整型的,出现卡浮点判断的情况还是比较少的。 最后算三角型…

PHP进程退出信号_一文吃透 PHP 进程信号处理

背景前两周老大给安排了一个任务,写一个监听信号的包。因为我司的项目是运行在容器里边的,每次上线,需要重新打包镜像,然后启动。在重新打包之前,Dokcer会先给容器发送一个信号,然后等待一段超时时间(默认1…

GitHub Copilot 现已登陆 Visual Studio!

激动人心的好消息来了,GitHub 在3月29日发布博客,宣布 Github Copilot 现在可以在 Visual Studio 中使用。我们知道 Visual Studio 的 IntelliCode 本身已经很智能了, 现在又迎来了 Copilot, 编程体验将进入新的篇章。如何安装? 首先,您…

经典实用SQL语句大全汇总

目 录 1.随机取3条记录 2.随机选记录 3.删除重复记录 4.创建数据库 5.列出表里的所有的列名 6.选择从10到15的记录 7.压缩数据库

java之写接口回调编程经验改进

1、问题 在一个类里面数据的变化需要在另外一个类里面动态得到,比如在我的异步任务里面下载的数据,需要在UI界面的ProgressDialog里面动态显示,我们需要在异步任务里面写个接口,然后接口里面有一些函数,至于在Progres…

Mac Ubuntu ----端口被占用

Mac下使用lsof(list open files)来查看端口占用情况,lsof 是一个列出当前系统打开文件的工具。 使用 lsof 会列举所有占用的端口列表: 1$ lsof使用less可以用于分页展示,如: 1$ lsof | less也可以使用 -i 查…

iOS 9音频应用播放音频之音量设置与声道设置

iOS 9音频应用播放音频之音量设置与声道设置 iOS 9音频应用音量设置 音量又称响度、音强,是指人耳对所听到的声音大小强弱的主观感受,其客观评价尺度是声音的振幅大小。在iOS 9音频应用的应用中,经常会出现播放的音乐音量过大或者过小。此时i…

nginx配置文件中的location中文详解

location 语法:location [|~|~*|^~] /uri/ { … }默认:否 上下文:server 这个指令随URL不同而接受不同的结构。你可以配置使用常规字符串和正则表达式。如果使用正则表达式,你必须使用 ~* 前缀选择不区分大小写的匹配或者 ~ 选择区分大小写的匹配。 确定 哪个locati…

php fpm工作原理,什么是phpfpm的工作原理?

什么是phpfpm的工作原理?发布时间:2020-07-13 15:12:53来源:亿速云阅读:181作者:Leah什么是phpfpm的工作原理?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多…

C#对象映射器之Mapster

简介Mapster是一个快,小巧,功能强大的对象映射.Net框架例子我有两个Model类且他们的属性一致,我们将 SourceObjectTest赋值给DestObjectTest该怎么做?SourceObjectTest sourceObject new SourceObjectTest(); sourceObject.Name …

如何关闭Struts2的webconsole.html

出于安全目的,在禁用了devMode之后,仍然不希望其他人员看到webconsole.html页面,则可以直接删除webconsole.html 的源文件, 它的位置存在于: 我们手工删除 struts2-core-*.jar\org\apache\struts2\interceptor\debuggi…

UIView 的基础

UIView•什么是控件?-屏幕上的所有UI元素都叫做控件,也有人叫做视图、组件-按钮(UIButton)、文本(UILabel)都是控件•控件的共同属性有哪些?-尺寸-位置-背景色-......-•苹果将控件的共同属性都…

记录平时编程或者阅读英文文档的时候不认识的英文单词

一、目的 英语虽然过了4级,但是还是很多英文单词不认识,为了以后能更好的阅读英文文档和函数的英文注释,记录自己不认识的英文单词,方便以后复习,这里后面会持续更新,因为放在网上这个平台不会弄丢。 二、…

php本地的调试安装,教你本地安装、运行、调试PHP程序

安装工具对学习PHP的新手来说,WINDOWS下环境配置是一件很困难的事;至少对于我来说本地调试PHP程序比登天还要困难,繁荣拖沓的各种程序。以前我博客程序用的是PJBLOG,本地的IIS就完全可以搞定,但是自从换了WordPress之后…