当前位置: 首页 > news >正文

聊聊Linux内核中内存模型

介绍

在Linux中二进制的程序从磁盘加载到内存,运行起来后用户态是使用pid来唯一标识进程,对于内核都是以task_struct表示。二进制程序中的数据段、代码段、堆都能提现在task_struct中。每一个进程都有自己的虚拟地址空间,虚拟地址空间包含几种区域,具体参照如下

在内核中进程分配内存时候并非立马给定虚拟内存对应的物理内存,而是分配虚拟内存的使用权。只有当进程真正访问申请的虚拟内存才会分配物理页帧并建立页表映射。就如下面的代码malloc仅仅是在当前的进程的地址空间内分配虚拟内存的使用权,分配物理页帧是在memset函数访问虚拟内存的时候。

void *ptr=malloc(sizeof(int));
memset(ptr,0,sizeof(int));

进程虚拟地址空间

之前聊过task_struct用来表示内核中的进程或者线程,在task_struct中有一个进程内存空间的描述符,用来描述进程的内部虚拟空间布局。这个结构非常大,我们会从task_struct->mm_struct->vm_area_struct从上往下的顺序简单介绍下

// 内核中用来表示进程或者线程的数据结构
struct task_struct {// 进程的内存空间描述符struct mm_struct        *active_mm;
};// 进程的虚拟内存空间描述符号
struct mm_struct {struct {// 进程是使用的所有虚拟内存的链表struct vm_area_struct *mmap;        /* list of VMAs */// 链表中的节点组成的红黑树struct rb_root mm_rb;// 当前进程最大的虚拟地址空间大小unsigned long task_size;    /* size of task vm space */// 页表的物理地址pgd_t * pgd;// 二进制代码的虚拟内存区域是从start_code到end_code来表示// 初始化区域虚拟内存用start_data和end_data来表示unsigned long start_code, end_code, start_data, end_data;// 动态变化的堆虚拟内存区域是从start_brk到brkunsigned long start_brk, brk, start_stack;// 参数列表的虚拟内存区域是从arg_start到arg_end// 环境变量的虚拟内促区域是从env_start到env_endunsigned long arg_start, arg_end, env_start, env_end;} __randomize_layout;
};// 用来表示各个虚拟内存区域的结构
struct vm_area_struct {// 虚拟内存的起始地址unsigned long vm_start;     /* Our start address within vm_mm. */// 虚拟内存的结束地址unsigned long vm_end;       /* The first byte after our end addresswithin vm_mm. */// 进程所使用的各个虚拟内存区域通过vm_prev和vm_next链表链接起来struct vm_area_struct *vm_next, *vm_prev;// 当查找虚拟地址存在于哪个区域时链表性能显然不行,通过vm_rb构建的红黑树查找struct rb_node vm_rb;// 指向属于哪一个mm_struct结构用来表示从属关系struct mm_struct *vm_mm;    /* The address space we belong to. */// 内存区域的标记pgprot_t vm_page_prot;unsigned long vm_flags;     /* Flags, see mm.h. */// vma的操作函数const struct vm_operations_struct *vm_ops;// 文件映射的偏移量unsigned long vm_pgoff;     // 如果是文件映射vm_file则是表示对应的文件指针struct file * vm_file;      /* File we map to (can be NULL). */void * vm_private_data;     /* was vm_pte (shared mem) */} __randomize_layout;

相关视频推荐

2024,彻底搞懂计算机的底层原理,linux内核源码分析教程,六大模块全面分析(内存管理、进程管理、设备驱动、网络协议栈、文件系统、中断管理及基础)icon-default.png?t=N7T8https://www.bilibili.com/video/BV1GT4y1t7Hs/

免费学习地址:Linux C/C++开发(后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全)

需要C/C++ Linux服务器架构师学习资料加qun579733396获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享

内存操作

这里涉及到的是文件映射和堆内存分配两种的情况

文件映射

用户态的文件映射是通过mmap系统调用进行实现,它可以绕靠文件系统的过程,利用内存指针快速访问文件数据。mmap新的系统调用对应的是内核中ksys_mmap_pgoff.

// mmap的系统调用的实现,底层是调用ksys_mmap_pgoff的函数
SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,unsigned long, prot, unsigned long, flags,unsigned long, fd, unsigned long, off)
{if (off & ~PAGE_MASK)return -EINVAL;return ksys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
}
// ksys_mmap_pgoff的具体定义如下
unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len,unsigned long prot, unsigned long flags,unsigned long fd, unsigned long pgoff)
{struct file *file = NULL;unsigned long retval;// 匿名文件映射,设置映射的文件if (!(flags & MAP_ANONYMOUS)) {audit_mmap_fd(fd, flags);file = fget(fd);// 大页方式} else if (flags & MAP_HUGETLB) {struct ucounts *ucounts = NULL;struct hstate *hs;hs = hstate_sizelog((flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);file = hugetlb_file_setup(HUGETLB_ANON_FILE, len,VM_NORESERVE,&ucounts, HUGETLB_ANONHUGE_INODE,(flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);}// 最核心的映射函数实现retval = vm_mmap_pgoff(file, addr, len, prot, flags, pgoff);return retval;
}// 调用底层的do_mmap函数实现映射
unsigned long vm_mmap_pgoff(struct file *file, unsigned long addr,unsigned long len, unsigned long prot,unsigned long flag, unsigned long pgoff)
{ret = do_mmap(file, addr, len, prot, flag, pgoff, &populate,&uf);return ret;
}// 最底层的文件映射的实现
unsigned long do_mmap(struct file *file, unsigned long addr,unsigned long len, unsigned long prot,unsigned long flags, unsigned long pgoff,unsigned long *populate, struct list_head *uf)
{struct mm_struct *mm = current->mm;vm_flags_t vm_flags;int pkey = 0;// 在线性区间找到未被使用并且足够大的地址空间addr = get_unmapped_area(file, addr, len, pgoff, flags);// 传入prot和flags设置vm_flagsvm_flags = calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) |mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;// 如果是文件映射,则通过find_inode找到inode并检查文件if (file) {struct inode *inode = file_inode(file);}addr = mmap_region(file, addr, len, vm_flags, pgoff, uf){// 检查虚拟地址空间容量限制if(!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT)){}// 检查是否有当前的vma有重叠如果有则进行munmap操作munmap_vma_range(mm, addr, len, &prev, &rb_link, &rb_parent, uf);// 与现有的vma进行合并vma = vma_merge(mm, prev, addr, addr + len, vm_flags,NULL, file, pgoff, NULL, NULL_VM_UFFD_CTX);if (vma) {goto out; }// 申请新的vm_area_struct结构vma = vm_area_alloc(mm);// 将新的vm_area_struct插入到mm_struct中的链表、红黑树以及对应文件的地址空间上的adress_space->i_mmap或者address_space->i_mmap_nolinear中vma_link(mm, vma, prev, rb_link, rb_parent);}return addr;
}

堆内存

在用户态申请内存和释放内存通过malloc/free库函数进行,它们的底层还是通过SYSCALL_DEFINE1(brk, unsigned long, brk)系统调用来完成。堆内存的扩大可以通过SYSCALL_DEFINE1(brk, unsigned long, brk)进行,如果需要缩小的空间则通过do_munmap实现。如果分配空间大于128KB(glibc源码中定义的MMAP_THRESHOLD),malloc使用sys_mmap2实现内存申请。不论是malloc还是calloc申请的是线性虚拟地址而非物理地址,连续的空间也是指的虚拟地址空间的连续。

// brk系统调用的实现
SYSCALL_DEFINE1(brk, unsigned long, brk)
{origbrk = mm->brk;// 检查资源的限制if (check_data_rlimit(rlimit(RLIMIT_DATA), brk, mm->start_brk,mm->end_data, mm->start_data))goto out;// page的对齐newbrk = PAGE_ALIGN(brk);oldbrk = PAGE_ALIGN(mm->brk);if (oldbrk == newbrk) {mm->brk = brk;goto success;}// 如果是是释放操作则执行__do_munmap调整指针的位置if (brk <= mm->brk) {int ret;mm->brk = brk;ret = __do_munmap(mm, newbrk, oldbrk-newbrk, &uf, true);goto success;}// 对应malloc的实现,申请新的vm_area_struct、插入到mm_struct中的list和rb树中// do_b rk_flags可以理解是mmap简单版的实现if (do_brk_flags(oldbrk, newbrk-oldbrk, 0, &uf) < 0)goto out;mm->brk = brk;success:populate = newbrk > oldbrk && (mm->def_flags & VM_LOCKED) != 0;if (downgraded)mmap_read_unlock(mm);elsemmap_write_unlock(mm);userfaultfd_unmap_complete(mm, &uf);if (populate)mm_populate(oldbrk, newbrk - oldbrk);return brk;out:mmap_write_unlock(mm);return origbrk;
}

相关文章:

聊聊Linux内核中内存模型

介绍 在Linux中二进制的程序从磁盘加载到内存&#xff0c;运行起来后用户态是使用pid来唯一标识进程&#xff0c;对于内核都是以task_struct表示。二进制程序中的数据段、代码段、堆都能提现在task_struct中。每一个进程都有自己的虚拟地址空间&#xff0c;虚拟地址空间包含几…...

docker自动化部署示例

前提 安装docker 、 docker-cpmpose、git、打包环境&#xff08;如meaven、jdk、node等&#xff09; 原理 git Dockerfile docker-compose 获取源码&#xff08;代码仓库&#xff09;获取可运行程序的镜像&#xff08;docker&#xff09;将打包后的程序放入镜像内&#xf…...

Redis精品案例解析:Redis实现持久化主要有两种方式

Redis实现持久化主要有两种方式&#xff1a;RDB&#xff08;Redis DataBase&#xff09;和AOF&#xff08;Append Only File&#xff09;。这两种方式各有优缺点&#xff0c;适用于不同的使用场景。 1. RDB持久化 RDB持久化是通过创建一个二进制的dump文件来保存当前Redis数据…...

Python | Leetcode Python题解之第14题最长公共前缀

题目&#xff1a; 题解&#xff1a; class Solution:def longestCommonPrefix(self, strs: List[str]) -> str:def isCommonPrefix(length):str0, count strs[0][:length], len(strs)return all(strs[i][:length] str0 for i in range(1, count))if not strs:return &quo…...

烧坏两块单片机,不知道原因?

没有看你的原理图&#xff0c;以下是造成烧毁芯片的几个环节&#xff1a; 1. 最大的可能性是你的单片机电机控制输出与电机驱动电路没有隔离。 我的经验&#xff0c;使用STM32控制电机&#xff0c;无论是直流电机脉宽调制&#xff0c;还是步进电机控制&#xff0c;控制电路与…...

SV学习笔记(八)

文章目录 SV入门练习基本数据类型字符串类型数组类型接口的定义与例化类的封装类的继承package的使用随机约束线程的同步线程的控制虚方法方法&#xff08;任务与函数&#xff09;SV用于设计 参考资料 SV入门练习 基本数据类型 有符号无符号、四状态双状态、枚举类型、结构体…...

Java反射常用方法

反射 作用&#xff1a; 对于任意一个对象&#xff0c;把对象所有的字段名和值&#xff0c;保存到文件中去利用反射动态的创造对象和运行方法 1. 获取字节码文件对象 方法描述Class.forName(String)通过类的全限定名字符串获取字节码文件对象。类字面量直接使用类的字面量获…...

go语言实现无头单向链表

什么是无头单向链表 无头单向链表是一种线性数据结构&#xff0c;它的每个元素都是一个节点&#xff0c;每个节点都有一个指向下一个节点的指针。"无头"意味着这个链表没有一个特殊的头节点&#xff0c;链表的第一个节点就是链表的头。 优点&#xff1a; 动态大小&…...

SpringBoot快速入门笔记(5)

文章目录 一、elemetnUI1、main.js2、App.vue3、fontAwesome 一、elemetnUI 开源前端框架&#xff0c;安装 npm i element-ui -S 建议查看官方文档 Element组件&#xff0c;这里是Vue2搭配elementUI&#xff0c;如果是vue3就搭配elementPlus&#xff0c;这里初学就以Vue2为例子…...

solidity(3)

地址类型 pragma solidity ^0.8.0;contract AddressExample {// 地址address public _address 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;address payable public _address1 payable(_address); // payable address&#xff0c;可以转账、查余额// 地址类型的成员uint256…...

笔记 | 编译原理L1

重点关注过程式程序设计语言编译程序的构造原理和技术 1 程序设计语言 1.1 依据不同范型 过程式(Procedural programming languages–imperative)函数式(Functional programming languages–declarative)逻辑式(Logical programming languages–declarative)对象式(Object-or…...

k8s存储卷 PV与PVC 理论学习

介绍 存储的管理是一个与计算实例的管理完全不同的问题。PersistentVolume 子系统为用户和管理员提供了一组 API&#xff0c;将存储如何制备的细节从其如何被使用中抽象出来。为了实现这点&#xff0c;我们引入了两个新的 API 资源&#xff1a;PersistentVolume 和 Persistent…...

【WPF应用32】WPF中的DataGrid控件详解与示例

在WPF&#xff08;Windows Presentation Foundation&#xff09;开发中&#xff0c;DataGrid控件是一个强大的数据绑定工具&#xff0c;它以表格的形式展示数据&#xff0c;并支持复杂的编辑、排序、过滤和分组等操作。在本文中&#xff0c;我们将详细介绍DataGrid控件的功能、…...

numpy,matplotilib学习(菜鸟教程)

所有内容均来自于&#xff1a; NumPy 教程 | 菜鸟教程 Matplotlib 教程 | 菜鸟教程 numpy模块 numpy.nditer NumPy 迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式。 for x in np.nditer(a, orderF):Fortran order&#xff0c;即是列序优先&#x…...

Web API(四)之日期对象节点操作js插件重绘和回流

Web API(四)之日期对象&节点操作&js插件&重绘和回流 日期对象实例化方法时间戳DOM 节点插入节点删除节点查找节点父子关系兄弟关系M端事件js插件重绘和回流进一步学习 DOM 相关知识,实现可交互的网页特效 能够插入、删除和替换元素节点能够依据元素节点关系查找…...

27.WEB渗透测试-数据传输与加解密(1)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;26.WEB渗透测试-BurpSuite&#xff08;五&#xff09; BP抓包网站网址&#xff1a;http:…...

山寨windows

我的目标是能够运行windows 下的大部分PE格式的程序&#xff0c;这一点通过实验已经证明完全是可行的。 PE格式主要有exe dll sys等文件&#xff0c;这三个文件可以用相同的函数解析&#xff0c; 主要有以下段组成&#xff0c; 1、文件头&#xff0c;包含DOS文件头、PE文件头…...

unity工程输出的log在哪里?

在编辑器里进行活动输出的log位置&#xff1a; C:\Users\username\AppData\Local\Unity\Editor\Editor.log ------------------------------------ 已经打包完成&#xff0c;形成的exe运行后的log位置&#xff1a; C:\Users\xxx用户\AppData\LocalLow\xx公司\xx项目...

【力扣】7. 整数反转

7. 整数反转 题目描述 给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] &#xff0c;就返回 0。 假设环境不允许存储 64 位整数&#xff08;有符号或无符号&#xff09;。 …...

Android Apk签名算法使用SHA256

Android apk签名算法使用SHA256 本文不介绍复杂的签名过程&#xff0c;说一下Android签名算法使用SHA256。 但是SHA1不是相对安全签名算法&#xff0c;SHA256更加安全一些。 一般大公司才会有这种细致的安全要求。 如何查看apk签名是否是SHA1还是SHA256 1、拿到apk文件&…...

2024.3.13力扣每日一题——最大二进制奇数

2024.3.13 题目来源我的题解方法一 贪心 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2864 我的题解 方法一 贪心 统计1的个数&#xff0c;满足要求的字符串的末尾一位一定是1&#xff0c;所以需要将一位1放到末尾&#xff0c;然后将剩余的1从最高位开始放&#xff0…...

2024.4.1力扣每日一题——故障键盘

2024.4.1 题目来源我的题解方法一 直接利用StringBuilder的反转函数方法二 字符数组 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2810 我的题解 方法一 直接利用StringBuilder的反转函数 使用StringBuilder构造结果&#xff0c;并利用其反转函数进行翻转 时间复杂度…...

第十四届蓝桥杯C/C++大学B组题解(一)

1、日期统计 #include <bits/stdc.h> using namespace std; int main() {int array[100] {5, 6, 8, 6, 9, 1, 6, 1, 2, 4, 9, 1, 9, 8, 2, 3, 6, 4, 7, 7,5, 9, 5, 0, 3, 8, 7, 5, 8, 1, 5, 8, 6, 1, 8, 3, 0, 3, 7, 9,2, 7, 0, 5, 8, 8, 5, 7, 0, 9, 9, 1, 9, 4, 4, 6,…...

4.网络编程-websocket(golang)

目录 什么是websocket golang中使用websocket Server端 Client端 什么是websocket WebSocket是一种在互联网上提供全双工通信的协议&#xff0c;即允许服务器和客户端之间进行双向实时通信的网络技术。它是作为HTML5的一部分标准化的&#xff0c;旨在解决传统HTTP协议在实…...

docker安装部署mysql后忘记root密码

应用场景是&#xff1a;用docker安装完mysql后&#xff0c;使用安装时候设置的密码登录不上MySQL&#xff1b; 1、修改docker映射出mysql的配置文件&#xff1a;my.cnf 在mysqld最下方添加skip-grant-tables进入安全模式&#xff08;随意一个密码即可登录mysql&#xff09; [m…...

c++的学习之路:14、list(1)

本章讲一下如何使用list&#xff0c;代码在文章末 目录 一、list介绍 二、增 三、删 四、查和改 五、交换 六、代码 一、list介绍 首先还是看一看官方文档的介绍如下图&#xff0c;如下方五点&#xff1a; 1. list是可以在常数范围内在任意位置进行插入和删除的序列式…...

huawei 华为交换机 配置 VLAN 聚合示例

组网需求 某公司拥有多个部门且位于同一网段&#xff0c;为了提升业务安全性&#xff0c;将不同部门的用户划分到不同VLAN 中&#xff0c;如 图 5-7 所示&#xff0c; VLAN2 和 VLAN3 属于不同部门。各部门均有访问Internet需求&#xff0c;同时由于业务需要&#xff0c;不同部…...

【QT+QGIS跨平台编译】056:【pdal-dimbuilder+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、pdal介绍二、dimbuilder介绍三、pdal下载四、文件分析五、pro文件六、编译实践七、生成Dimension.hpp八、生成pdal_features.hpp一、pdal介绍 PDAL(Point Data Abstraction Library)是一个开源库,用于处理点云数据的获取、过滤、转换、分析和…...

【Python】探索Python中的aiohttp:构建高效并发爬虫

后来 我总算学会了 如何去爱 可惜你 早已远去 消失在人海 后来 终于在眼泪中明白 有些人 一旦错过就不再 &#x1f3b5; HouZ/杨晓雨TuTu《后来》 在数据密集和网络密集的任务中&#xff0c;提高程序的执行效率是非常重要的。Python作为一门强大的编程语言…...

创建真实项目vue2项目

1. 创建 vue create 项目名 2. 选择自定义 3. 勾选以下必备选项 4.选择使用vue2 5. 选择哈希模式&#xff08;n&#xff09;; css选择Less 6. ESLint校验 选择 7. 保存&#xff08;按照默认&#xff09; 8. 在哪里添加ESLint文件 9. 要不要把这个改成将来的预设&am…...

水文化建设网站/有没有专门做营销的公司

1.事务 数据库**事务( transaction)**是访问并可能操作各种数据项的一个数据库操作序列&#xff0c;这些操作要么全部执行,要么全部不执行&#xff0c;是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。 比如&#xff0c;我们去银行转账&…...

app开发源码/网站排名优化查询

C/C&#xff1a;rand()函数 rand()函数的头文件&#xff1a;#include<stdlib.h> 该函数产生的随机数随机性差&#xff0c;速度慢&#xff0c;周期小(0-32767) 用法如下所示&#xff1a; #include<stdio.h> #include<stdlib.h> #include<time.h> int ma…...

国家税务总局网站官网/做推广app赚钱的项目

jagub 于 2009-06-18 08:10:22发表:或者在安装的时候提供可选择项目&#xff0c;岂不是更人性化大宝 于 2009-06-17 22:10:56发表:我安装时总是断网拨线(内网中)&#xff0c;免得?嗦HRF 于 2009-06-17 21:41:48发表:学习中。。。。jagub 于 2009-06-17 15:47:09发表:其实大家老…...

做网站流程、/广东做seo的公司

设计模式原则 1、开-闭原则&#xff08;OCP Open Close Principle&#xff09; 面向对象可利用设计(OOD)的第一块基石&#xff0c;就是“开-闭原则&#xff08;Open-Closed principle,简称OCP&#xff09;&#xff0c;它的核心含意是&#xff1a;一个好的设计应该能够容纳新的…...

phpstudy 网站空白/站长之家 站长工具

数字信号的最佳接收性能的研究 数字信号的最佳接收性能的研究The best digital signal reception perance摘要&#xff1a;本文研究数字信号最佳接收性能&#xff0c;运用MATLAB 进行编程仿真2ASK,2FSK,2PSK调制解调过程&#xff0c;按照错误概率最小作为“最佳”的准则比较各种…...

建设网站需要独立ip吗/谷歌google浏览器

在终端用户看来&#xff0c;USB 设备为主机提供了多种多样的附加功能&#xff0c;如文件传输&#xff0c;声音播放等&#xff0c;但对 USB 主机来说&#xff0c;它与所有 USB 设备的接口都是一致的。一个 USB 设备由3个功能模块组成&#xff1a;USB 总线接口、USB 逻辑接口和功…...