Linux操作系统分析实验-用户与内核共享内存,实验二

news2024/10/10 21:46:48

Linux操作系统分析实验-多线程与内核模块编程,实验一_实验一 多线程与内核模块编程-CSDN博客

一、实验目的

1、理解Linux进程地址空间、虚拟内存、物理内存的概念;

2、理解物理内存分配和回收原理。

3、利用链表实现动态内存分配。

4、了解共享内存原理,并深入理解用户与内核共享内存过程。

二、实验内容

1、利用strace 命令跟踪进程调用 exec 函数将可执行文件载入内存时,代码段,数据段,bbs 段,stack 段都通过 mmap 函数映射到内存空间的过程;

2、利用free命令查看当前系统的内存使用情况;

3、 利用链表结构,malloc函数和 free函数实现将终端输入的一系列字符串用链表的形式保存下来。然后再将这些数据组装起来,回显到输出终端。

4、 利用vmalloc()和vfree()内核函数编写内核模块实现内核和用户共享内存。

三、实验原理

1、静态内存与动态内存

按分配内存空间的方式不同,一个程序所使用的内存区域可以分为静态内存与动态内存。在程序开始运行时由系统分配的内存称为静态内存,在程序运行过程中由用户自己申请分配的内存称为动态内存。

静态内存的申请是由编译器来分配的。当程序执行时,系统就为变量分配所需的内存空间,至使用该变量的函数执行完毕返回时,自动释放所占用的内存空间。用户并不需要了解分配内存的具体细节,也不需要时刻考虑由于程序结束前未释放所占用的内存空间而带来的可用内存泄漏。同时,静态内存也是不通过指针而使用变量的唯一方法。

使用动态内存时,用户可以根据需要随时申请内存,使用完毕后手动将此内存区释放。在实际应用中非常方便。

2、使用链表进行动态内存的分配

虽然使用动态内存可以方便地使用内存,但动态内存也有局限性,就是在数据输入到程序之前必须知道数据的大小,以便申请相应的动态内存。

链表是一种动态地进行存储分配的结构。链表中的各个元素是一个结构,每个元素称为链表的一个结点。此结构中包含有一个指向此结构的指针,用于指向链表中的下一个结点。链表的最后一个结点的指针NULL,表示链表结束。

3、进程地址空间

程序一旦被执行就成为一个进程,内核就会为每个运行的进程提供了大小相同的虚拟地址空间,这使得多个进程可以同时运行而又不会互相干扰。

每个进程通过系统调用进入内核,Linux内核空间由系统内的所有进程共享。从进程的角度看,每个进程拥有4GB的虚拟地址空间。每个进程有各自的私有用户空间(0-3GB),这个空间对系统中的其他进程是不可见的。最高的1GB内核空间为所有进程以及内核所共享。

每个程序编译链接后形成的二进制映像文件有一个代码段(Text)和数据段(BSS和Data)。进程运行时须有独占的堆(Heap)和栈(Stack)空间。进程要映射的文件被映射到内存映射区(Memory Mapping Region)。

Linux 把进程的用户空间划分为若干个区,便于管理,这些区间称为虚拟内存域(简称vma )。 一个进程的用户地址空间主要由 mm_struct 结构和 vm_area_struct 结构来描述

4、进程用户空间的创建

每个进程都有自己独立的地址空间,那么,进程的地址空间到底是什么时候创建的?实际上,当fork()系统调用在创建新进程时也为该进程创建完整的用户空间。那么这个用户空间是如何被创建的呢?实际上是通过拷贝或共享父进程的用户空间来实现的,即内核调用copy_mm()函数,为新进程建立所有页表和mm_struct结构(通常,每个进程都有自己的用户空间,但是调用clone(  )函数创建内核线程时共享父进程的用户空间)。

5、虚存映射

当调用exec()系统调用开始执行一个进程时,进程的可执行映像(包括代码段、数据段,堆和栈等)必须装入到进程的用户地址空间。如果该进程用到了任何一个共享库,则共享库也必须装入到进程的用户空间。由此可看出,Linux并不将映像装入到物理内存,相反,可执行文件只是被映射到进程的用户空间中。这种将可以执行文件映像映射到进程用户空间的方法被称为“虚存映射”。

6、页故障与物理内存的分配

一个程序在装载时,执行文件的指令和数据加载进内存,但并没有真正的装入物理内存,只是通过ELF文件头部信息建立起可执行文件与虚拟地址空间的映射关系而已,真正加载过程将在发生缺页异常处理时才进行。

在访问用户态虚拟地址空间时,如果没有映射物理地址,通过请页机制发出缺页异常。缺页异常陷入内核,分配物理地址空间,并将可执行文件内容装载到该内存页中,与用户态虚拟地址建立映射关系,也就是填充页表。找到所需的内容在可执行文件中的位置,将指令寄存器设置为可执行文件入口,然后把控制权交换给进程,启动运行。进程运行时,CPU访问的是用户空间的虚地址。Linux仅把当前要使用的少量页面装入内存,需要时再通过请页机制将特定的页面调入内存。当要访问的页不在内存时,产生一个页故障并报告故障原因。

这其中涉缺页异常处理机制和物理内存的分配与回收。

当用户进程通过调用系统调用申请内存时,首先陷入内核,建立虚拟地址空间的映射,获得一块虚拟内存区VMA。当进程对这块虚存区进行访问时,如果物理内存尚未分配,那么此时发生一个缺页异常,通过get_free_pages 申请一个或多个物理页面,并将此物理内存和虚拟内存的映射关系写入页表。

四、实验步骤

要求写出实验过程和思路(用文字表述,或画流程图,或写出伪代码 都可以)。

1、利用strace 命令跟踪进程调用 exec 函数将可执行文件载入内存时,代码段,数据段,bbs 段,stack 段都通过 mmap 函数映射到内存空间的过程;

打开终端,执行 strace -e trace=mmap,execve 可执行文件路径 命令,跟踪可执行文件的加载过程。

观察输出,查看mmap系统调用的参数,了解代码段、数据段、bbs段、stack段的映射情况。

2、利用free命令查看当前系统的内存使用情况;

打开终端,执行 free 命令。

查看输出,了解系统的内存使用情况。

3、利用链表结构,malloc函数和 free函数实现将终端输入的一系列字符串用链表的形式保存下来。然后再将这些数据组装起来,回显到输出终端。

使用链表结构保存输入的字符串,每个节点存储一个字符串。

利用malloc函数动态分配内存来存储每个字符串。

利用free函数释放链表占用的内存。

将链表中的字符串组装起来,并回显到输出终端。

4、利用vmalloc()和vfree()内核函数编写内核模块实现内核和用户共享内存。

  • 编写内核模块,使用vmalloc函数在内核空间分配共享内存。
  • 在模块初始化函数中初始化共享内存,将一些数据存储到共享内存中。
  • 通过字符设备接口实现mmap函数,将共享内存映射到用户空间。
  • 编写用户空间程序,调用mmap函数获取共享内存的映射地址。
  • 在用户空间程序中访问共享内存,进行读写操作。
  • 在模块卸载函数中释放共享内存。

五、实验数据及源代码

(学生必须提交程序源代码,并有注释)

1.

strace -e trace=mmap,execve /home/fengshu/first(可执行文件路径)

2.

free

该命令将显示系统总内存、已使用内存和空闲内存的信息。

3.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义链表节点的结构
struct Node {
    char data[100];
    struct Node* next;
};
// 将新节点添加到链表的函数
void addNode(struct Node** head, const char* data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    strncpy(newNode->data, data, sizeof(newNode->data) - 1);
    newNode->next = *head;
    *head = newNode;
}
// 显示链表的函数
void displayList(struct Node* head) {
    struct Node* current = head;
    while (current != NULL) {
        printf("%s\n", current->data);
        current = current->next;
    }
}
// 释放链表占用的内存的函数
void freeList(struct Node* head) {
    struct Node* current = head;
    while (current != NULL) {
        struct Node* temp = current;
        current = current->next;
        free(temp);
    }
}
int main() {
    struct Node* head = NULL;
    char input[100];
    // 从终端读取一系列字符串
    printf("input chars(exit:end):\n");
    while (1) {
        scanf("%s", input);
        if (strcmp(input, "exit") == 0) {
            break;
        }
        addNode(&head, input);
    }
    // 显示链表
    printf("\nList content:\n");
    displayList(head);
    // 释放链表占用的内存
    freeList(head);
    return 0;
}

4.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/mm.h>

#define MODULE_NAME "shared_memory_module"

static char* shared_memory;

static int my_open(struct inode* inode, struct file* filp) {
    return 0;
}

static int my_release(struct inode* inode, struct file* filp) {
    return 0;
}

static int my_mmap(struct file* filp, struct vm_area_struct* vma) {
    int size = vma->vm_end - vma->vm_start;
    int result;

    // 将共享内存映射到进程的地址空间
    result = remap_pfn_range(vma, vma->vm_start, virt_to_phys(shared_memory) >> PAGE_SHIFT, size, vma->vm_page_prot);

    if (result < 0) {
        printk(KERN_INFO "映射共享内存失败\n");
        return -EIO;
    }

    return 0;
}

static struct file_operations my_fops = {
    .open = my_open,
    .release = my_release,
    .mmap = my_mmap,
};

static int __init my_init(void) {
    shared_memory = vmalloc(PAGE_SIZE); // 分配共享内存

    if (!shared_memory) {
        printk(KERN_INFO "分配共享内存失败\n");
        return -ENOMEM;
    }

    // 初始化共享内存(例如,存储一些数据)
    strcpy(shared_memory, "来自内核的问候!");

    // 注册字符设备
    if (register_chrdev(0, MODULE_NAME, &my_fops)) {
        printk(KERN_INFO "注册字符设备失败\n");
        vfree(shared_memory);
        return -EFAULT;
    }

    printk(KERN_INFO "模块加载成功\n");
    return 0;
}

static void __exit my_exit(void) {
    unregister_chrdev(0, MODULE_NAME); // 注销字符设备
    vfree(shared_memory); // 释放共享内存
    printk(KERN_INFO "模块卸载\n");
}

module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");

六、实验结果分析(截屏的实验结果,与实验结果对应的实验分析)

1)实验结果与实验程序、实验步骤、实验原理的对应分析;

1、利用strace 命令跟踪进程调用 exec 函数将可执行文件载入内存时,代码段,数据段,bbs 段,stack 段都通过 mmap 函数映射到内存空间的过程;

2、利用free命令查看当前系统的内存使用情况;

3、利用链表结构,malloc函数和 free函数实现将终端输入的一系列字符串用链表的形式保存下来。然后再将这些数据组装起来,回显到输出终端。

4、利用vmalloc()和vfree()内核函数编写内核模块实现内核和用户共享内存。

2)实验过程中的问题及原因和解决办法。

在使用共享内存之前,必须确保正确初始化。否则,可能会导致未定义的行为或错误的结果。解决方法: 在共享内存分配后,执行必要的初始化步骤,确保共享内存处于有效状态。

如果多个进程或线程同时访问共享内存,可能导致竞态条件或数据不一致性。解决方法: 使用同步机制(如信号量、互斥锁等)来确保对共享内存的安全访问。

七、实验思考题

1、进程的地址空间(mm_struct结构和vm_area_strcut结构)到底是什么时候被映射的? 

进程的地址空间在进程创建时被初始化。在Linux中,mm_struct结构表示进程的内存描述符,而vm_area_struct结构则表示虚拟内存区域。地址空间的映射发生在以下几个时刻:

  • 进程创建: 当一个新的进程被创建时,它会继承父进程的地址空间,这时地址空间会被映射到新的进程。
  • 执行可执行文件: 当进程调用exec函数加载可执行文件时,新的代码段、数据段等会被映射到地址空间。
  • 动态内存分配: 当进程使用malloc等动态内存分配函数时,内存会被动态映射到地址空间。
  • 文件映射: 当进程使用mmap函数将文件映射到内存时,文件的内容会被映射到地址空间。

2、什么是内存泄漏?为什么会发生内存泄漏?

内存泄漏是指程序在运行过程中动态分配的内存空间没有被正确释放,导致系统中的可用内存逐渐减少。

为什么会发生内存泄露:

  • 未释放动态分配的内存: 当程序动态分配内存(使用malloc或new等函数),但在程序运行结束前没有正确释放这些内存时,就会导致内存泄漏。
  • 丢失对动态分配内存的引用: 当程序丢失了对动态分配内存的指针,无法再进行释放操作时,也会导致内存泄漏。

3、什么是野指针?为什么会出现野指针?

野指针是指指向已经被释放或者无效的内存地址的指针。

出现野指针的原因主要有两种:

  • 指针未被初始化: 当一个指针被声明但未被初始化时,它的值是不确定的,可能指向任意内存地址,这种情况下使用该指针就会导致野指针问题。
  • 指针指向的内存已经被释放: 当程序使用free或delete等函数释放了动态分配的内存后,如果继续使用指向该内存的指针,就会引发野指针问题。

4、通过 mmap()进行内存映射,多进程是否安全?

通过mmap()进行内存映射时,多进程是可以安全地共享内存的。mmap()函数创建的映射区域可以被多个进程访问,实现了进程间的共享内存。但是需要注意在多进程共享内存时要确保正确同步数据,以避免竞争条件和数据一致性问题。

5、用户空间(进程)是否有高端内存概念?

没有高端内存的概念

6、64 位内核中有高端内存吗?

在64位系统中,通常不再限制用户空间和内核空间的大小,因此不存在32位系统中的"高端内存"概念。

7、在32 位和 64 位系统上,用户进程能访问多少物理内存?内核代码能访问多少物理内存?

在32位系统上,用户进程一般能够访问的物理内存受限于系统的地址空间限制,通常为4GB。内核代码能够访问的物理内存也受限于1GB的内核空间。

在64位系统上,用户进程能够访问的物理内存理论上可以非常大,取决于系统硬件和操作系统的支持。64位系统的地址空间范围极大,一般可以支持数十TB的物理内存。内核代码也能够访问非常大的物理内存。

8、在物理内存为 1G 的计算机中,能否调用 malloc(1.6G )?为什么?

在物理内存为1G的计算机中,调用malloc(1.6G)可能会导致分配失败。这是因为malloc在分配内存时需要找到足够大的连续空闲内存块,如果系统中没有足够大的连续空闲内存块,分配就会失败。物理内存大小限制了malloc函数能够分配的最大内存块的大小

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

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

相关文章

VMtools安装办法解决本地与虚机拷贝

一、打开虚拟机选项-重新安装VMware Tools 二、等待虚拟机开启&#xff0c;点开运行(WinR)输入D:/setup.exe 前提正常引用虚拟机光盘介质&#xff0c;保证光驱位置处于D盘&#xff0c;下一步进行安装完成。

Golang | Leetcode Golang题解之第466题统计重复个数

题目&#xff1a; 题解&#xff1a; func getMaxRepetitions(s1 string, n1 int, s2 string, n2 int) int {n : len(s2)cnt : make([]int, n)for i : 0; i < n; i {// 如果重新给一个s1 并且s2是从第i位开始匹配 那么s2可以走多少位&#xff08;走完了就从头开始走p1, p2 :…

Jenkins pipeline语法笔记

Jenkins pipeline 简介Jenkins Pipeline 优势DSL 是什么 pipeline支持两种语法&#xff1a;声明式pipeline语法&#xff1a;Pipelineagent Pipeline 声明式语法DeclarativeenvironmentoptionsparameterstriggerstoolsinputwhenParallel Pipeline Scripted语法流程控制Declarati…

【HarmonyOS】HMRouter使用详解(三)生命周期

生命周期&#xff08;Lifecycle&#xff09; 使用HMRouter的页面跳转时&#xff0c;想实现和Navigation一样的生命周期时&#xff0c;需要通过新建生命周期类来实现对页面对某一个生命周期的监控。 新建Lifecycle类 通过继承IHMLifecycle接口实现生命周期接口的方法重写。 通过…

20240904 华为笔试 二叉树消消乐

文章目录 题目解题思路代码BUG 代码最终代码题目 题目描述 给定原始二叉树和参照二叉树(输入的二叉树均为满二叉树,二叉树节点的值范围为[1,1000],二叉树的深度不超过1000),现对原始二叉树和参照二又树中相同层级目值相同的节点进行消除,消除规则为原始二叉树和参照二又树中…

进程概念三

1&#xff0c;运行状态R 1&#xff0c;理论&#xff1a; 在cpu中&#xff0c;有一个结构体&#xff1a;runqueue组成的一个双向链表&#xff0c;里面记录着对应的进程的代码和数据&#xff0c;存在内存中随时准备被调度&#xff0c;这种时候就叫做运行状态 2&#xff0c;why&a…

25西安电子科技大学考研预报名人数信息—公布

01报名信息直播 西安电子科技大学之前考研收集信息表现在公布&#xff0c;本次收集涉及到833、834、893&#xff08;原953&#xff09;专业&#xff0c;即计算机科学与技术学院、人工智能学院、网络与信息安全学院、卓越工程师学院 对于大家想提问的问题&#xff0c;学长学姐将…

AI智能聊天问答系统源码+AI绘画系统+图文搭建部署教程,文生图图生图,TTS语音识别输入,AI智能体,文档分析

一、前言 人工智能的快速进步吸引了全球的瞩目&#xff0c;各式AI应用如绘图、语言模型和视频处理等已在多个领域获得应用。这些技术不仅加速了科技的创新&#xff0c;也在艺术创作、内容生产和商业实践等方面显示了其巨大潜力。例如&#xff0c;AI语言模型极大提升了内容自动…

Cursor 与 DeepSeek API 的完美融合

在当今的编程领域中&#xff0c;选择合适的工具对于提高编程效率和质量至关重要。今天&#xff0c;我们将深入探讨如何将强大的 AI 辅助编程工具 Cursor 与优秀的 DeepSeek API 进行配置&#xff0c;以实现更加高效的编程体验。 一、Cursor&#xff1a;强大的 AI 辅助编程工具…

前端实现-搜索关键字标红处理

1、实现效果 2、代码实现 searchNotes(data, value) {const searchTerms = value.split( );const aData = [];for (let i = 0; i < data.length; i++) {const item = data[i];let titleMatches = true;let gaishuMatches = true;for (const term of searchTerms) {if (!ite…

Docker 的使用-01

一、Docker 设置和镜像源 1.1、设置 #查看 Docker 信息 docker version docker info#守护线程启动&#xff1a; systemctl daemon-reload 重启Docker服务&#xff1a; systemctl restart docker#关闭Docker服务 sudo systemctl stop docker#启动Docker服务 systemctl start d…

finereport制作带刷新和滚动的明细表

1、数据库查询 SELECT * FROM S订单 limit 602、配置页面内容 里面配置 订单明细 right(now(), 8) FORMAT(today(), "EEEE", "Locale.UK") today()3、时间按秒刷新 # 全页面刷新&#xff0c;则可用以下js: setInterval(“self.location.reload();”,1000…

AI 仅有大模型吗?AI Agent 究竟有多牛?

今天来和大家聊一个当下科技领域特别火爆的概念——AI Agent&#xff01; 前世界首富在其个人博客上写道&#xff1a; AI Agent&#xff08;AI智能体/助理/助手&#xff09;“将彻底改变计算机使用方式&#xff0c;并颠覆软件行业”。 他还预言“Android、iOS和Windows都是平…

喜讯!迈威通信TSN产品通过“时间敏感网络(TSN)产业链名录计划”评测,各项指标名列前茅

TSN技术&#xff0c;作为推动企业网络化与智能化转型的关键力量&#xff0c;已成为工业网络迈向下一代演进的共识方向&#xff0c;正加速重构工业网络的技术架构与产业生态。为响应这一趋势&#xff0c;工业互联网产业联盟携手中国信息通信研究院及50余家产学研用单位&#xff…

leetcode---素数,最小质因子,最大公约数

1 判断一个数是不是质数(素数) 方法1&#xff1a;依次判断能否被n整除即可&#xff0c;能够整除则不是质数&#xff0c;否则是质数 方法2&#xff1a;假如n是合数&#xff0c;必然存在非1的两个约数p1和p2&#xff0c;其中p1<sqrt(n)&#xff0c;p2>sqrt(n)。 方法3&…

【Unity学习笔记】解决疑似升级Win11或使用Unity6导致Unity旧版本无法打开的问题

【Unity学习笔记】解决疑似升级Win11或使用Unity6导致Unity旧版本无法打开的问题 一句话省流&#xff1a; 确保项目地址没有任何中文&#xff0c;重新申请个许可证&#xff0c;然后该咋就咋&#xff0c;完事。 ——————————————————————————————…

攻防世界(CTF)~Reverse-easyRE1

题目介绍 下载附件后一个32位一个64位 64位的放到ExeinfoPE查看一下有无壳子&#xff08;无壳&#xff09; 放IDA看一下伪代码&#xff0c;习惯性看一下main函数&#xff0c;直接发现了flag flag{db2f62a36a018bce28e46d976e3f9864}

解锁智慧之门:十大知识管理工具深度剖析

在当今信息爆炸的时代&#xff0c;如何高效地管理和利用知识已成为企业和个人发展的重要挑战。为了帮助大家更好地应对这一挑战&#xff0c;本文将深度剖析十大知识管理工具&#xff0c;这些工具不仅能够帮助我们更好地组织、存储和分享知识&#xff0c;还能提升我们的工作效率…

华为OD机试 - 芯片资源占用(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

Linux_进程概念详解

本篇文章为作者学习Linux时所作总结&#xff0c;可能会有总结不足或疏漏之处&#xff0c;如有发现请各路大神批评指正 什么是进程&#xff1f; 课本上说&#xff0c;进程是程序的一个执行实例&#xff0c;正在执行的程序。对&#xff0c;也不对&#xff0c;我称之为正确的废话…