Linux 内存管理一

  • 磁盘
  • 文件描述符fd和文件指针(FILE结构体)
    • 文件描述符fd
    • FILE结构体
    • 与文件描述符相关的三张表
  • 虚拟文件系统(VFS)
    • 主要作用
    • Linux中文件系统逻辑关系架构
    • VFS的核心数据结构
  • 文件读写过程
    • 读过程
    • 写过程
  • 参考博客

磁盘

  文件存储在硬盘上,硬盘的最小存储单位叫做”扇区”(Sector)。每个扇区储存512字节(磁盘不能定位到每一个地址,职能定位到扇区,所以读写操作常常是以一整个扇区为单位,例如要变某一个地方的值,是将整个扇区读出来,然后更改完后在写回去)。
  操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个”块”(block)。这种由多个扇区组成的”块”,是文件存取的最小单位。”块”的大小,最常见的是4KB,即连续八个 sector组成一个 block。

文件描述符fd和文件指针(FILE结构体)

文件描述符fd

  linux中一切接文件,而所有文件都通过文件描述符来操作,文件描述符是一个非负的整数,每当打开现有文件或者创建新文件,内核会像进程都会返回一个文件描述符,一个新创建的进程中,默认有三个文件描述符,0、1、2,如果创建或者打开新的文件,则会返回3,即没增加一个文件,则该进程返回的文件描述符+1。
  每个进程都有一个文件描述符的表,用来管理文件描述符,父进程如果fork子进程的话,子进程会继承这个文件描述符的表。相同的文件可以有不同的进程打开,一个文件也能被一个进程打开多次,会生成多个文件描述符,但是都是指向的同一个文件。
  进程打开文件过程:
  执行open通过系统调用打开文件,该进程获得文件描述符之后能操作文件。并且进程会为该文件创建file对象,将file对象的指针存入进程描述符表。即文件描述符fd是一个整数,他对应着文件描述符表中的key,根据这个key能找的val,即文件指针。

struct files_struct {atomic_t count; /* 共享该表的进程数 */rwlock_t file_lock; /* 保护以下的所有域,以免在tsk->alloc_lock中的嵌套*/int max_fds; /*当前文件对象的最大数*/int max_fdset; /*当前文件描述符的最大数*/int next_fd; /*已分配的文件描述符加1*/struct file ** fd; /* 指向文件对象指针数组的指针 */fd_set *close_on_exec; /*指向执行exec( )时需要关闭的文件描述符*/fd_set *open_fds; /*指向打开文件描述符的指针*/fd_set close_on_exec_init;/* 执行exec( )时需要关闭的文件描述符的初 值集合*/fd_set open_fds_init; /*文件描述符的初值集合*/struct file * fd_array[32];/* 文件对象指针的初始化数组*/
};

FILE结构体

//C语言文件指针域文件描述符之间可以相互转换
int fileno(FILE * stream)
FILE * fdopen(int fd, const char * mode)struct _iobuf {char *_ptr;          //缓冲区当前指针int   _cnt;char *_base;         //缓冲区基址int   _flag;         //文件读写模式int   _file;         //文件描述符int   _charbuf;      //缓冲区剩余自己个数int   _bufsiz;       //缓冲区大小char *_tmpfname;
};
typedef struct _iobuf FILE;

  FILE结构体中包含文件描述符和缓冲区。
  注意:文件描述符和文件指针的区别

int fd = open("");

  这里的fd代表的是文件描述符,每个进程的PCB中保存着一份文件描述符表,这个fd表示已打开的文件在这个表中的索引。每个表项都有一个指针指向打开的文件

FILE *fd;代表的是文本文件,使用fopen、fread、fwrite进行读写

  这里的fd表示文件指针,通过FILE结构体来构建。FILE包括一个IO缓冲区和文件描述符,可以理解为FILE包含了文件描述符
  文件描述符和文件指针的转换:

int fileno(FILE *stream);
FILE *fdopen(int fd, const char *mode);

与文件描述符相关的三张表

  1. 进程中的文件描述符表
struct files_struct {atomic_t count; /* 共享该表的进程数 */rwlock_t file_lock; /* 保护以下的所有域,以免在tsk->alloc_lock中的嵌套*/int max_fds; /*当前文件对象的最大数*/int max_fdset; /*当前文件描述符的最大数*/int next_fd; /*已分配的文件描述符加1*/struct file ** fd; /* 指向文件对象指针数组的指针 */fd_set *close_on_exec; /*指向执行exec( )时需要关闭的文件描述符*/fd_set *open_fds; /*指向打开文件描述符的指针*/fd_set close_on_exec_init;/* 执行exec( )时需要关闭的文件描述符的初 值集合*/fd_set open_fds_init; /*文件描述符的初值集合*/struct file * fd_array[32];/* 文件对象指针的初始化数组*/
};
struct task_struct {//...struct files_struct *files // 进程级别的文件描述符表//...
};
  1. linux内核维护的文件描述符表
struct file
{struct list_head f_list; /*所有打开的文件形成一个链表*/struct dentry *f_dentry; /*指向相关目录项的指针*/struct vfsmount *f_vfsmnt; /*指向VFS安装点的指针*/struct file_operations *f_op; /*指向文件操作表的指针*/mode_t f_mode; /*文件的打开模式*/loff_t f_pos; /*文件的当前位置*/unsigned short f_flags; /*打开文件时所指定的标志*/unsigned short f_count; /*使用该结构的进程数*/unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;/*预读标志、要预读的最多页面数、上次预读后的文件指针、预读的字节数以及预读的页面数*/int f_owner; /* 通过信号进行异步I/O数据的传送*/unsigned int f_uid, f_gid; /*用户的UID和GID*/int f_error; /*网络写操作的错误码*/unsigned long f_version; /*版本号*/void *private_data; /* tty驱动程序所需 */
};

  内核对所有打开的文件通过一个链表建立链接。并将链表中的每个节点称为文件句柄,一个打开文件的句柄存储了打开文件的全部信息,包括:当前操作文件的偏移、标识状态(open时的flag)、文件权限、文件属性、对inode的引用等。
2. 文件系统的inode表

struct inode {struct hlist_node    i_hash;struct list_head    i_list;struct list_head    i_sb_list;struct list_head    i_dentry;unsigned long        i_ino;atomic_t        i_count;unsigned int        i_nlink;uid_t            i_uid;gid_t            i_gid;dev_t            i_rdev;   //该成员表示设备文件的inode结构,它包含了真正的设备编号。u64            i_version;loff_t            i_size;#ifdef __NEED_I_SIZE_ORDEREDseqcount_t        i_size_seqcount;
}

  将硬盘格式化为ext文件系统是,硬盘会被分数据区(block)和inode区,block存放数据,inode存放文件包含的信息。包括文件字节数、占用了那几个磁盘块、文件属性和权限、文件时间戳、链接树(内核的文件描述符表中有多少文件指向这个inode)、文件数据block的位置,以及inode编号。(通过df -i指令可以看到inode信息,通过ls -il最前面的一列就是inode编号)。

虚拟文件系统(VFS)

  进程所有的文件操作都通过VFS,由VFS来适配各种底层不同的文件系统,完成实际的文件操作。
  VFS是内核的一个子系统,VFS向上提供统一的操作接口。
  一个具体的文件系统想要被Linux支持,必须按照VFS的规范编写自己的操作函数,同时将自己的操作细节对内核的其他子系统隐藏
  通俗的说,VFS就是定义了一个通用文件系统的接口层和适配层,一方面为用户进程提供了一组统一的访问文件,目录和其他对象的统一方法,另一方面又要和不同的底层文件系统进行适配。具体应用:例如mount、umount、sysfs、chown、mkdir等,特别,异步IO的select和poll是VFS。

主要作用

主要作用:

  1. 支持多种具体文件系统直接的相互访问(例如ext的文件系统通过mount指令在某个目录下挂在Fat文件系统的U盘,粘贴复制移动等操作都不被影响是因为VFS的原因)
  2. 接受系统的调用,read、write、open
  3. 对具体文件系统数据结构进行抽象,以统一的数据结构进行管理
  4. 接受其他子系统的操作

Linux中文件系统逻辑关系架构

VFS的核心数据结构

  1. 超级块(superblock)模块:用于保存一个文件系统的所有元数据,相当于这个文件系统的信息库,为其他的模块提供信息。因此一个超级块可代表一个文件系统。文件系统的任意元数据修改都要修改超级块。超级块对象是常驻内存并被缓存的。
  2. 索引节点(inode)模块:管理一个具体的文件,是文件的唯一标识,一个文件对应一个inode。通过inode可以方便的找到文件在磁盘扇区的位置。同时inode模块可链接到address_space模块,方便查找自身文件数据是否已经缓存。
  3. 目录项(dentry)模块:管理路径的目录项。比如一个路径 /home/foo/hello.txt,那么目录项有home, foo, hello.txt。目录项的块,存储的是这个目录下的所有的文件的inode号和文件名等信息。其内部是树形结构,操作系统检索一个文件,都是从根目录开始,按层次解析路径中的所有目录,直到定位到文件。
  4. 文件(file)模块:包含所有内核已经打开的文件。已经打开的文件对象由open系统调用在内核中创建,也叫文件句柄。打开文件列表模块中包含一个列表,每个列表表项是一个结构体struct file,结构体中的信息用来表示打开的一个文件的各种状态参数。
  5. 文件操作(file_operations)模块。这个模块中维护一个数据结构,是一系列函数指针的集合,其中包含所有可以使用的系统调用函数,例如open、read、write、mmap等。每个打开文件(打开文件列表模块的一个表项)都可以连接到file_operations模块,从而对任何已打开的文件,通过系统调用函数,实现各种操作。
  6. address_space模块,它表示一个文件在页缓存中已经缓存了的物理页。它是页缓存和外部设备中文件系统的桥梁。如果将文件系统可以理解成数据源,那么address_space可以说关联了内存系统和文件系统。

文件读写过程

  linux系统采用虚拟内存机制后,页是虚拟内存管理的最小单位。有两个概念需要区分一下:buffer chahe和page cache,buffer是面向块设备的,而page(页)是面向虚拟内存的。文件io之和page缓存交互,不和内存交互。

读过程

  1. 通过read函数进程系统调用发起读请求
  2. 内核检查进程的文件描述符表定位到文件指针
  3. 根据文件指针找到目录项和inode等信息
  4. 根据inode计算出要读取的地址和页的信息
  5. 通过inode找到文件对应的address_space
  6. 在address_space中访问该文件的页缓存树,查找对应的页缓存结点:如果页缓存命中,那么直接返回文件内容;如果页缓存缺失,那么产生一个页缺失异常,创建一个页缓存页,同时通过inode找到文件该页的磁盘地址,读取相应的页填充该缓存页;重新进行第6步查找页缓存;

写过程

  1. 前5步和读文件一致,在address_space中查询对应页的页缓存是否存在:
  2. 如果页缓存命中,直接把文件内容修改更新在页缓存的页中。写文件就结束了。这时候文件修改位于页缓存,并没有写回到磁盘文件中去。
  3. 如果页缓存缺失,那么产生一个页缺失异常,创建一个页缓存页,同时通过inode找到文件该页的磁盘地址,读取相应的页填充该缓存页。此时缓存页命中,进行第6步。
  4. 一个页缓存中的页如果被修改,那么会被标记成脏页。脏页需要写回到磁盘中的文件块。有两种方式可以把脏页写回磁盘:手动调用sync()或者fsync()系统调用把脏页写回,pdflush进程会定时把脏页写回到磁盘。同时注意,脏页不能被置换出内存,如果脏页正在被写回,那么会被设置写回标记,这时候该页就被上锁,其他写请求被阻塞直到锁释放。

参考博客

  • https://blog.csdn.net/qq_20817327/article/details/107093167?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165371513316782246462636%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165371513316782246462636&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-8-107093167-null-null.nonecase&utm_term=%E5%AD%98%E5%82%A8&spm=1018.2226.3001.4450

linux内存管理一相关推荐

  1. Windows内存管理和linux内存管理

    windows内存管理 windows 内存管理方式主要分为:页式管理,段式管理,段页式管理. 页式管理的基本原理是将各进程的虚拟空间划分为若干个长度相等的页:页式管理把内存空间按照页的大小划分成片或 ...

  2. 万字长文,别再说你不懂Linux内存管理了(合辑),30 张图给你安排的明明白白...

    之前写了两篇详细分析 Linux 内存管理的文章,读者好评如潮.但由于是分开两篇来写,而这两篇内容其实是有很强关联的,有读者反馈没有看到另一篇读起来不够不连贯,为方便阅读这次特意把两篇整合在一起,看这 ...

  3. 别再说你不懂Linux内存管理了,10张图给你安排的明明白白!

    来自:后端技术学堂 过去的一周有点魔幻,有印象的有三个新闻:天猫总裁绯闻事件,蘑菇街裁员,不可能打工的周某也放出来了.三件事,两件和互联网行业相关,好像外面的世界很是精彩啊!吃瓜归吃瓜,学习还是不能落 ...

  4. Linux内存管理原理【转】

    转自:http://www.cnblogs.com/zhaoyl/p/3695517.html 本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址 ...

  5. Linux内存管理【转】

    转自:http://www.cnblogs.com/wuchanming/p/4360264.html 转载:http://www.kerneltravel.net/journal/v/mem.htm ...

  6. Linux内存管理之高端内存映射

    一:引子 我们在前面分析过,在linux内存管理中,内核使用3G->4G的地址空间,总共1G的大小.而且有一部份用来做非连续空间的物理映射(vmalloc).除掉这部份空间之外,只留下896M大 ...

  7. Linux内存管理原理

    本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址又叫线性地址.linux没有采用分段机制,所以逻辑地址和虚拟地址(线性地址)(在用户态,内核态逻 ...

  8. Linux内存管理 (2)页表的映射过程

    专题:Linux内存管理专题 关键词:swapper_pd_dir.ARM PGD/PTE.Linux PGD/PTE.pgd_offset_k. Linux下的页表映射分为两种,一是Linux自身的 ...

  9. Linux内存管理 (4)分配物理页面

    专题:Linux内存管理专题 关键词:分配掩码.伙伴系统.水位(watermark).空闲伙伴块合并. 我们知道Linux内存管理是以页为单位进行的,对内存的管理是通过伙伴系统进行. 从Linux内存 ...

  10. Linux 交换内存空间原理(swap)(Linux内存管理)(cgroups)

    文章目录 什么是swap? 为什么需要swap? swap的缺点? 到底要不要swap? 内存不够用 内存勉强够用 内存充裕 桌面环境 服务器环境 swap大小配置多少比较合适? 怎么配置swap? ...

最新文章

  1. 程序员面试题精选100题(50)-树的子结构[数据结构]
  2. SRAM(静态随机存储器)
  3. Redis应用案例 查找某个值的范围
  4. ASP.NET Core MVC 之依赖注入 View
  5. virtual box一直正在加载文件_Linux基础导航与文件管理
  6. (84)FPGA显示激励(display)
  7. 游族网络:中诚信国际将公司主体及游族转债列入信用评级观察名单
  8. linux cpu load命令,Linux性能检测常用的10个基本命令
  9. Android学习视频精品课程汇总(持续更新)
  10. cnnvd爬取漏洞信息
  11. MATLAB牛拉法计算潮流,Matlab牛拉法潮流计算程序
  12. Smart3D系列教程3之 《论照片三维重建中Smart3D几个工作模块的功能意义》
  13. Spring框架---全面详解【无比详细,学习总结】
  14. pdf文件如何生成目录 wps_怎样快速为WPS文档增加目录
  15. 计算机怎么设置桌面密码忘了,win7忘记开机密码怎么办?[多图]
  16. SAR变化检测的性能指标(kappa系数)——简化版
  17. css实现遮罩层动画
  18. 代码中出现的奇怪问题原因
  19. 小程序下单账号与支付账号不一致不让支付_微信小程序支付流程
  20. 毕业之后从事前端工作月薪大概多少?

热门文章

  1. 社区教育计算机培训材料,远程教育在社区教育培训中的实效性
  2. java 活锁 线程饿死,JAVA并发编程(四)线程死锁、饥饿、活锁
  3. QQ、支付宝、微信收款码三合一开源程序
  4. vue elementUI 标签切换时 数据不更新
  5. powershell + python 批量更改图片大小
  6. mmog游戏开发之业务篇
  7. 南农计算机考研历年分数线,2020南京农业大学考研复试分数线已公布
  8. 网易邮箱CSRF漏洞
  9. cpu performance profiling
  10. Ubuntu20.04下NVIDIA驱动+anaconda3+cuda+cudnn+pytorch安装