04_14缺页异常,虚拟空间加深印象,匿名页,文件页

news2024/11/25 7:03:00

前言

写代码想知道某段时间内存够不够用 想更清楚高低水位 清楚虚拟ram和物理ram的关系

CPU通过地址总线可以访问连接在地址总线上的所有外设,包括物理内存、I0设备等等, 但从CPU发出的访问
地址并非是这些外设在地址总线上的物理地址,
而一个虚拟地址,由MMU将虚拟地址转换成物理地址再从地址总线上发出,
MMU上的这种虚拟地址和物理地址的錾关系是需要创建的,并且MMU还可以设备这个物理面是否可以进行写操作,
当没有创建一个虚拟地址到物理地址的映射,或者创建了这样的映射,
但是那个物理面不可写的时候,MMU将会通知CPU产生一个缺页异常。
或者说有时候用户空间或者内核空间使用malloc 这种创建了一块区域 并不是真的在物理ram上分配了页
只有使用到的时候 会发生一个缺页异常 后续才有一系列流程来分配这个页

虚拟内存空间加深印象

抄一下某个博主的图
在 Linux 操作系统中,虚拟地址空间的内部又被分为内核空间和用户空间两部分,不同位数的系统,地址空间的范围也不同。比如最常见的 32 位和 64 位系统
在这里插入图片描述
32 位系统的内核空间占用 1G,位于最高处,剩下的 3G 是用户空间;
64 位系统的内核空间和用户空间都是 128T,分别占据整个内存空间的最高和最低处,剩下的中间部分是未定义的。空洞区域
虽然每个进程都各自有独立的虚拟内存,但是每个虚拟内存中的内核地址,其实关联的都是相同的物理内存。这样,进程切换到内核态后,就可以很方便地访问内核空间内存。
在这里插入图片描述
最后到每一个进程中用户空间的分布情况
在这里插入图片描述
通过这张图你可以看到,用户空间内存,从低到高分别是 7 种不同的内存段:
程序文件段,包括二进制可执行代码;
已初始化数据段,包括静态常量;
未初始化数据段,包括未初始化的静态变量;
堆段,包括动态分配的内存,从低地址开始向上增长;
文件映射段,包括动态库、共享内存等,从低地址开始向上增长(跟硬件和内核版本有关);也是文件页(下面有说)
栈段,包括局部变量和函数调用的上下文等。栈的大小是固定的,一般是 8 MB。当然系统也提供了参数,以便我们自定义大小;
在这 7 个内存段中,堆和文件映射段的内存是动态分配的。比如说,使用 C 标准库的 malloc() 或者 mmap() ,就可以分别在堆和文件映射段动态分配内存。

VMA

linux内核中,这样的区域被称之为虚拟内存区域(virtual memory areas),简称 VMA。
一个vma就是一块连续的线性地址空间的抽象,它拥有自身的权限(可读,可写,可执行等等) ,
每一个虚拟内存区域都由一个相关的 struct vm_area_struct 结构来描述。
从进程的角度来讲,VMA 其实是虚拟空间的内存块,一个进程的内存资源由多个内存块组成,所以,一个进程的描述结构 task_struct 中首先包含Linux的内存描述符 struct mm_struct 结构。
下面的图为了说明这些结构体都连其他结构体 能看下面的源码
在这里插入图片描述

发生缺页异常跑入的函数_do_ page_ fault源码分析

下面的代码会对产生异常的情况进行判断 直到最后才是因为 用户空间或者内核空间
给产生异常的地方分配物理ram页

static noinline voic 
    do_ page_ fault(struct pt_ regs *regs, unsigned 1ong error_code,
        unsigned 1ong address ){
    struct vm_ _area_ struct *vma; // 定义结构体指针变量:表示-个独立的虚拟内存区域
    struct task_ struct *tsk; //进程描述符
    struct mm_ _struct *mm; // 进程内存描述符
    int fault, major = 0;
    unsigned int flags = FAULT_ _FLAG ALLOW_ RETRY| FAULT_ _FLAG_ _KILLABLE;
    //获取当前CPU正在运行的进程的进程描述符
    //然后获取进程的内存描述符
    tsk = current;
    mm = tsk- >mm; .
    //缺页地址位于内核空间,并不代表异常发生于内核空间,有可能是用户状态访问了内核空间的地址
    if (unlikely(fault_ _in_ _kernel_ space(address))) {
        if (!(error. _code & (PF_ _RSVD | PF_ _USER | PF. _PROT))) {
        //检查发生缺页地址是否在vmalloc区,是则进行相应的处理,主要是从内核主页表向进程页表同步数据
        if (vmalloc_ _fault(address) >= 0)
            return;
        if (kmemcheck_ fault(regs, address, error. code))
            return;
        }
        //检查是否是TLB (转换后备缓冲区,又称为页表缓存)导致候的性能延迟
        if (spurious_ fault(error_ code, address))
            //由于异常地址位于内核态,触发内核异常,因为vmalloc区的缺页异常,内核态的缺页异常只能
            //发生在vmalloc区,如果不是,那就是内核异常。
            bad_ area_ nosemaphore(regs, error_ code, address, NULL);
            return;
    }
    //可以缩短因缺页异常所导致的差中断时长
    if (user_mode(regs)) {
    1ocal_irq_enable();
    error_ code |= PF_ USER;
    flags |= FAULT_ FLAG_ USER;
    } else{
    if (regs->flags & X86_ EFLAGS_ IF)
    local_ _irq_ enable();
    if (unlikely(!down_ read_ try1ock(&mm- >mmap_ sem))) { .
    // 缺页发生在内核.上下文,此情况发生缺页的地址只能位于用户态地址空间
    if ((error_ code & PF_ USER) ==&&
    !search_ exception. _tables(regs->ip)) {
    bad_area_ nosemaphore(regs, error_ code, address, NULL);
    return;
    }
retry: //如果发生在用户态或者是有exception talbe, 说明不是内核异常
    down_ read( &mm- >mmap_ sem);
    } else {
    /*
    * The above down_ read_ trylock() might have succeeded in
    * which case We'll have missed the might_ sleep() from
    down_ read():*/
    might_ sleep();
    }
    //在当前进程的地址空间中查找发生异常的地址对应的VMA
    vma = find_ vma(mm, address);
    //如果没有找到VMA,则释放信号量
    if (unlikely(!vma)) {
    bad_ _area(regs, error. code, address );
    return;
    }

    //找到VMA,且发生异常的虛拟地址位于VMA的有效范围内,则为正常的缺页异常,请求调页,分配物理内存
    if (likely(vma->vm_ _start <= address))
        goto good_area;
    //如果异常地址不是位于紧挨着堆栈区域,同时又没有相应VMA,则进程访问造成非法地址,进入bad_area处理
    if (unlikely(!(vma->Vm_ _flags & VM_ GROWSDOWIN))) {
    bad_ _area(regs, error_ code, address);
    return;
    //表示缺页异常地址位于堆栈区,需要扩展堆栈,说明(堆栈区的虛拟地址空间也是动态分配和扩展的,不是
    //一开始就分配好的。)
    if (unlikely(expand_ stack(vma, address))) {
    bad_ _area(regs, error. code, address);
    return;
    /*
    0k, we have a good Vm_ area for this memory access, so
    we can handle it.. .
    */
    //说明: 正常的缺页异常, 进行请求调页,分配物理内存
good_area:
    if (unlikely(access_ error(error. code, vma))) {
    bad_ area_ access_ error(regs, error. code, address, vma);
    return;
    //从函数handle_ mm_ fault开始的部分,是所有处理器架构共用的部分
    //负责处理用户空间的缺页错误异常。
    fault = handle_ mm_ faultkvma, address, flags);
    major |= fault & VM_ FAULT_ MAJOR;
    }


用户空间异常

上面代码执行到用户空间异常会进行判断 反正就是来生成物理ram页
用户空间页错误异常是指进程访问用户虚拟地址生成的页错误异常,可以分为两种情况: .
进程在用户模式下访问用户虚拟地址,生成页错误异常。
进程在内核模式下访问用户虚拟地址,生成页错误异常。
进程通过系统调用进入内核模式,系统调用传入用户空间的缓冲区,进程在内核模式下访问用户空间的缓冲区。
如果虚拟内存区域使用标准巨型页,则调用函数hugetlb_ fault处理标准巨型页的页错误异常。
如果虚拟内存区域使用普通页,则调用_ handle_ mm_ fault处理普通页的页错误异常。

发生页异常处理

应用程序通过 malloc 函数申请内存的时候,实际上申请的是虚拟内存,此时并不会分配物理内存。
当应用程序读写了这块虚拟内存,CPU 就会去访问这个虚拟内存, 这时会发现这个虚拟内存没有映射到物理内存, CPU 就会产生缺页中断,进程会从用户态切换到内核态,并将缺页中断交给内核的 Page Fault Handler (缺页中断函数)处理。
缺页中断处理函数会看是否有空闲的物理内存,如果有,就直接分配物理内存,并建立虚拟内存与物理内存之间的映射关系。
如果没有空闲的物理内存,那么内核就会开始进行回收内存的工作,回收的方式主要是两种:直接内存回收和后台内存回收。

后台内存回收(kswapd):在物理内存紧张的时候,会唤醒 kswapd 内核线程来回收内存,这个回收内存的过程异步的,不会阻塞进程的执行。
直接内存回收(direct reclaim):如果后台异步回收跟不上进程内存申请的速度,就会开始直接回收,这个回收内存的过程是同步的,会阻塞进程的执行。

如果直接内存回收后,空闲的物理内存仍然无法满足此次物理内存的申请,那么内核就会放最后的大招了 ——触发 OOM
(Out of Memory)机制。

匿名页(anonymous pages)

匿名页,没有文件背景的页面(即没有与磁盘文件存在任何映射关系的内存页面),如stack,heap,数据段,共享内存

文件页(file-backed pages)

文件页,即与磁盘文件存在映射关系的内存页(有文件背景的页面),例如进程代码段、文件的映射页等 ,他们有对应的硬盘文件,
因此如果要交换,可以直接和硬盘对应的文件进行交换。内存紧张时,非dirty的文件页可以直接drop掉,所以这个也算作MemAvailable中。

继续回到刚刚的函数

什么情况下会发生匿名页缺页异常呢?
函数的局部变量比较大,或者函数调用的层次比较深,导致当前栈不够用,需要扩大栈;
进程调用malloc,从堆申请了内存块,只分配虚拟内存区域,还没有映射到物理页,第
一次访问时触发缺页异常。
进程直接调用mmap,创建匿名的内存映射,只分配了虚拟内存区域,还没有映射到物
理页,第一次访问时触发缺页异常。

何时会触发文件页的缺页异常呢?
启动程序的时候,内核为程序的代码段和数据段创建私有的文件映射,映射到里程的虚
拟地址空间,第- -访问的时候触发文件页的缺页异常。
进程使用mmap创建文件映射,把文件的一个区间映射到进程的虚拟地址,第一-次访问
的时候触发文件页的缺页异常。

参考文章
https://blog.csdn.net/qq_34827674/article/details/107042163

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

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

相关文章

idea集成chatGPT,免费使用的bito神器

什么是Bito&#xff1f; Bito是一款在IntelliJ IDEA编辑器中的插件&#xff0c;Bito插件是由ChatGPT团队开发的&#xff0c;它是ChatGPT团队为了提高开发效率而开发的一款工具。ChatGPT团队是一支专注于自然语言处理技术的团队&#xff0c;他们开发了一款基于GPT的自然语言处理…

Springboot整合RabbitMq,详细使用步骤

Springboot整合RabbitMq&#xff0c;详细使用步骤 1 添加springboot-starter依赖2 添加连接配置3 在启动类上添加开启注解EnableRabbit4 创建RabbitMq的配置类&#xff0c;用于创建交换机&#xff0c;队列&#xff0c;绑定关系等基础信息。5 生产者推送消息6 消费者接收消息7 生…

优化堆排序(Java 实例代码)

目录 优化堆排序 Java 实例代码 src/runoob/heap/HeapSort.java 文件代码&#xff1a; 优化堆排序 上一节的堆排序&#xff0c;我们开辟了额外的空间进行构造堆和对堆进行排序。这一小节&#xff0c;我们进行优化&#xff0c;使用原地堆排序。 对于一个最大堆&#xff0c;首…

Azure概念介绍

云计算定义 云计算是一种使用网络进行存储和处理数据的计算方式。它通过将数据和应用程序存储在云端服务器上&#xff0c;使用户能够通过互联网访问和使用这些资源&#xff0c;而无需依赖于本地硬件和软件。 发展历史 云计算的概念最早可以追溯到20世纪60年代的时候&#x…

阿里云Alibaba Cloud Linux镜像系统介绍_常见问题解答FAQ

阿里云服务器操作系统Alibaba Cloud Linux镜像怎么样&#xff1f;可以代替CentOS吗&#xff1f;Alibaba Cloud Linux兼容性如何&#xff1f;有人维护吗&#xff1f;漏洞可以修复吗&#xff1f;Alibaba Cloud Linux完全兼容CentOS&#xff0c;并由阿里云官方免费提供长期维护。 …

数据统计与可视化的Dash应用程序

在数据分析和可视化领域&#xff0c;Dash是一个强大的工具&#xff0c;它结合了Python中的数据处理库&#xff08;如pandas&#xff09;和交互式可视化库&#xff08;如Plotly&#xff09;以及Web应用程序开发框架。本文将介绍如何使用Dash创建一个简单的数据统计和可视化应用程…

SpringBoot复习:(44)MyBatisAutoConfiguration

可以看到MyBatisAutoConfiguration引入了MyBatisProperties这个属性&#xff1a; MyBatisAutoConfiguration中配置了一个SqlSessionFactoryBean,代码如下&#xff1a; 可以配置mybatis-config.xml,需要配置文件里指定&#xff1a; mybatis.config-locationclasspath:/mybat…

ImportError: cannot import name ‘MutableMapping‘ from ‘collections‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

【FreeRtos基础入门】任务状态

文章目录 前言一、任务状态1.阻塞状态(Blocked)2.暂停状态(Suspended)3.就绪状态(Ready) 总结 前言 本freertos使用stm32系列单片机&#xff0c;使用其他的也可以&#xff0c;如esp系列等… 任务管理是实时操作系统&#xff08;RTOS&#xff09;的核心功能之一&#xff0c;它…

VMware Workstation中安装了Windows7系统但是VMware Tools选项为灰色及无法安装的解决方法

一、问题描述 当我们在使用VMware Workstation安装好了Windows7系统后;该安装好的Windows7系统并不能自动适配WMware的界面,只能在中间显示很小的一部分内容;此时我们就需要给Windows7系统安装VMware Tools工具; 问题一:WMware中的【安装VMware Tools】选项则是灰色的无法…

最强自动化测试框架Playwright(21)-测试生成器inspector

测试生成器 运行该命令时&#xff0c;将打开两个窗口&#xff0c;一个浏览器窗口&#xff0c;可以在其中与要测试的网站进行交互&#xff0c;另一个是Playwright Inspector窗口&#xff0c;可以在其中记录测试&#xff0c;然后将其复制到编辑器中。 使用该命令运行测试生成器…

7.9 SpringBoot实战 拷贝工具类,扩展BeanUtils.copyProperties

文章目录 前言一、拷贝普通对象Bean1.1 基础的Bean拷贝1.2 支持忽略某些属性1.3 支持忽略字段值为null的属性1.4 通用的Bean拷贝1.4.1 拷贝时可指定忽略属性1.4.2 拷贝时外加忽略null属性 二、拷贝集合对象List2.1 拷贝时可指定忽略属性2.2 拷贝时外加忽略null属性 三、拷贝分页…

HOT92-最小路径和

leetcode原题链接&#xff1a;最小路径和 题目描述 给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 说明&#xff1a;每次只能向下或者向右移动一步。 示例 1&#xff1a; 输入&#xff1a;…

基础堆排序(Java 实例代码)

目录 基础堆排序 一、概念及其介绍 二、适用说明 三、过程图示 四、Java 实例代码 src/runoob/heap/Heapify.java 文件代码&#xff1a; 基础堆排序 一、概念及其介绍 堆排序&#xff08;Heapsort&#xff09;是指利用堆这种数据结构所设计的一种排序算法。 堆是一个近…

① vue复习。从安装到使用

vue官网&#xff1a;cn.vuejs.org vue安装 cnpm install -g vue/cli 查看是否安装成功 vue --version 创建一个项目 vue create vue-demo(项目名称) 这个取消掉。空格可选中或者取消。 运行项目&#xff1a; cd 进入到项目下 npm run serve 运行成功后&#xff0c;访问这…

面对算力瓶颈,如何利用CPU解决全链路智能编码?

编者按&#xff1a;英特尔是半导体行业和计算创新领域的全球领先厂商。与合作伙伴一起&#xff0c;英特尔推动了人工智能、5G、智能边缘等转折性技术的创新和应用突破&#xff0c;驱动智能互联世界。不久前&#xff0c;英特尔正式发布了第四代英特尔至强可扩展处理器&#xff0…

计算机网络-物理层(二)- 传输方式

计算机网络-物理层&#xff08;二&#xff09;- 传输方式 串型传输与并行传输 串行传输:是指数据是一个比特一个比特依次发送的&#xff0c;因此在发送端和接收端之间&#xff0c;只需要一条数据传输线路即可 并行传输:是指一次发送n个比特而不是一个比特&#xff0c;因此发送…

前端架构师的能力要求:打造可靠、灵活和可扩展的Web应用

随着互联网技术迅猛发展&#xff0c;现代Web应用程序变得越来越复杂且功能强大。作为一名前端架构师&#xff0c;在这个快节奏且竞争激烈的环境中&#xff0c;你需要具备广泛而深入地技术知识&#xff0c;并且有能力设计、开发和维护高度可靠、灵活和可扩展性强的Web应用。 深入…

popen/pclose 函数

函数作用 如果说system在一定程度上是execl的优化版&#xff0c;那么popen就一定程度上是system的优化版&#xff0c;使用popen不仅可以运行代码&#xff0c;还可以获取运行的输出结果&#xff08;但是system和exec族函数还是非常重要的&#xff0c;也有自己的特定应用场景&am…

从0开始搭建ns3环境以及NetAnim简单使用

一、环境准备 ns3是基于GNU/Linux平台使用C开发的工具软件&#xff0c;在windows系统中安装使用ns3环境&#xff0c;可以使用虚拟机VMware并安装ubuntu系统来实现&#xff0c;现将本教程所用到的虚拟机和系统镜像放到网盘提供下载 名称链接提取码VMware Workstation 17 Proht…