转自:https://blog.csdn.net/qq_17019203/article/details/85051627

问题:open(2)函数打开文件是否将文件内容加载到内存空间

首先,文件打开后都会产生一个文件描述符fd,这个文件描述符其实是记录在PCB的文件描述符表中,而这个文件描述符实质上是一个结构体,用来存放跟打开文件相关的信息,基于此前提,我产生了两种假设

1、文件描述符结构体中只存储了文件在硬盘中的相应地址信息,并不将文件内容加载到内存中,这样做的好处是减少内存空间的占用,但大大增加了运行的时间(cpu存取内存数据的速度约ns级别,cpu存取硬盘数据的速度约为60000ns)。

2、文件描述符结构体为文件在内存中分配了地址空间来存放文件内容,这样做的好处是增加了运行速度,不足是当文件太大时严重占用内存空间。

3、如果问题2正确就产生了另一个问题,这块地址空间的大小和分配规则是什么?

接下来是我的探索过程和代码

第一步:我用open(2)函数打开了一个文件,设置连续读取文件,读取的间隔为3秒。

第二步:在读取的过程中我将还没被读取完的文件删除(另外打开一个bash,用rm命令删除)

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc,char *argv[])
{
int fd;
char buf[128];
int read_size,write_size;
//open a file with read and write
fd = open(argv[1],O_RDWR);
if(fd == -1)
{
perror("open");
return 1;
}
while(1)
{
read_size = read(fd,buf,2);
if(read_size == 0) break;
write(1,buf,read_size);
sleep(3);
}
//close fd
close(fd);
return 0;
}
下面是运行结果:

bash 1

[sun@localhost file_func]$ ./a.out hello
#include <stdio.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
int link_flag;
link_flag = link(argv[1],argv[2]);
if(link_flag == -1)
{
perror("link");
return 1;
}
if(link_flag == 0)
printf("creat hard link success...\n");

return 0;
}
bash 2

[sun@localhost file_func]$ rm hello
通过以上的结果我们能看出,在文件还没被读取完时将文件删除不会影响读取程序继续读取文件内容

结论1:用open(2)函数打开文件会将文件的内容加载到内存空间

接下来我们要探索的是,这个分配的地址空间大小上限是多少,文件类型的不同会不会产生不同的结果等问题

补充:

以上实验还存在一种可能性,就是rm 的原理和unlink是一样的(即rm是通过unlink封装的),等待程序运行完才会删除文件(阻塞删除),虽然删除文件操作是在文件执行完以后,但只要执行unlink文件马上就会消失看不到(在系统界面上消失,但在硬盘上还存在)

为了探索rm是不是通过unlink封装,我又进行了以下操作

一、创建虚拟映像使用rm命令

二、通过strace命令获取rm运行时产生的系统调用,命令如下

strace -f -F -o ./log.txt a.out
 三、在系统调用里查找是否存在unlink函数

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(void)
{
pid_t pid;
//creat child process
pid = fork();
if(pid == -1)
{
perror("fork");
return 1;
}
//child process
if(pid == 0)
{
//load a memory
int ex_flag=execlp("/bin/rm","rm","hello",NULL);
if(ex_flag == -1)
{
perror("execlp");
return 2;
}
return 0;
}
//father process
else
{
wait(NULL);
}

return 0;
}
 通过strace产生的结果如下

mmap(0x3f02d8e000, 18600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3f02d8e000
13697 close(3) = 0
13697 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0665bb5000
13697 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0665bb4000
13697 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0665bb3000
13697 arch_prctl(ARCH_SET_FS, 0x7f0665bb4700) = 0
13697 mprotect(0x3f02d89000, 16384, PROT_READ) = 0
13697 mprotect(0x3f0241f000, 4096, PROT_READ) = 0
13697 munmap(0x7f0665bb6000, 51177) = 0
13697 brk(0) = 0x187b000
13697 brk(0x189c000) = 0x189c000
13697 open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
13697 fstat(3, {st_mode=S_IFREG|0644, st_size=99158576, ...}) = 0
13697 mmap(NULL, 99158576, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f065fd22000
13697 close(3) = 0
13697 ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
13697 newfstatat(AT_FDCWD, "hello", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
13697 geteuid() = 500
13697 newfstatat(AT_FDCWD, "hello", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
13697 faccessat(AT_FDCWD, "hello", W_OK) = 0
13697 unlinkat(AT_FDCWD, "hello", 0) = 0
13697 close(0) = 0
13697 close(1) = 0
13697 close(2) = 0
13697 exit_group(0) = ?
13696 <... wait4 resumed> NULL, 0, NULL) = 13697
13696 --- SIGCHLD (Child exited) @ 0 (0) ---
13696 exit_group(0) = ?
我们可以看到倒数第8行出现了一个unlinkat系统调用函数,根据unlinkat函数的定义,第三个参数取0时,unlinkat等价于unlink。

通过以上分析,我有以下结论:

1、open(2)函数在打开文件时,是否将文件内容加载到内存空间目前无法得知,在学习的时候老师的理论是linux在读取文件时候会将文件的地址内容加载到内存,而非文件的内容。

2、第一个实验结果主观上来看,因为在删除掉被读取文件后文件还能继续读取,所以open函数打开文件是将文件内容加载到内存空间的。

但通过客观分析,我们发现我们所认为的“rm删除文件,文件不在系统界面显示就是被删除了”这种想法是不对的,因为rm删除文件是调用了unlinkat系统函数,所以虽然在文件被读取时候我们看不到被读取文件在系统中显示,但此时文件还是存在于硬盘中的,只有当被读取文件被读取完成后才会真正的被删除。
————————————————
版权声明:本文为CSDN博主「虚渊玄」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_17019203/article/details/85051627

linux函数深入探索——open函数打开文件是否将文件内容加载到内存空间的更多相关文章

  1. 利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载

    简述 可能大家都知道,php中有一个函数叫debug_backtrace,它可以回溯跟踪函数的调用信息,可以说是一个调试利器. 好,来复习一下 01 one(); 02 03 function one ...

  2. (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】

    原文地址:http://www.cnblogs.com/melonblog/archive/2013/05/09/3062303.html 原文作者:豆浆油条 - melon 本文示例代码测试环境是W ...

  3. angularjs ocLazyLoad分步加载js文件,angularjs ocLazyLoad按需加载js

    用angular有一段时间了,平日里只顾着写代码,没有注意到性能优化的问题,而今有时间,于是捋了捋,讲学习过程记录于此: 问题描述:由于采用angular做了网页的单页面应用,需要一次性在主布局中将所 ...

  4. linux的虚拟内存是4G,而每个进程都有自己独立的4G内存空间,怎么理解?

    问: linux的虚拟内存是4G,而每个进程都有自己独立的4G内存空间,怎么理解? 每个进程所拥有的4G独立的虚拟内存空间是什么意思?linux系统的虚拟4G空间中,高位的1G是用于系统内核运行的,那 ...

  5. win7,vs2010,asp.net项目中修改外部js文件,在调试时加载的还是旧文件

    win7,vs2010,asp.net项目中修改外部js文件,在调试时加载的还是旧文件 我杀过 w3wp.exe和asp.net_state的进程,重启 iis admin的服务,都还是不行. 只是把 ...

  6. java动态编译类文件并加载到内存中

    如果你想在动态编译并加载了class后,能够用hibernate的数据访问接口以面向对象的方式来操作该class类,请参考这篇博文-http://www.cnblogs.com/anai/p/4270 ...

  7. maven工程中防止mapper.xml文件被漏掉、未加载的方法

    maven工程中防止mapper.xml文件被漏掉.未加载的方法 就是在pom.xml文件中添加以下内容 <!-- 如果不添加此节点mybatis的mapper.xml文件都会被漏掉. --&g ...

  8. hibernate之xml映射文件关系维护,懒加载,级联

    一:关系维护 --->inverse默认值false,表示不放弃关系的维护.   --->inverse="true"配置在那一端,表示那一端xml对应的po放弃关系的 ...

  9. PE文件从文件加载到内存,再从内存读取,然后存盘到文件

    // mem.cpp : 定义控制台应用程序的入口点. //PE文件从文件加载到内存,再从内存读取,然后存盘到文件 #include "stdafx.h" #include < ...

随机推荐

  1. SQL基础知识整理

    建议:关键字和函数名全部大写:数据库名称.表名称.字段名称全部小写:分号结尾.但是大小写语句不区分,本人讨厌大写(英语菜,不能一眼看出内容),所以全部小写.[]看情况可有可无,{}花括号的内容必须要有 ...

  2. [RN] React Native 使用 realm 数据库

    React Native 使用 realm  数据库 realm 是一款专为移动 ​ 端开发的高性能数据库,其宣称自己是最快的 react-native 数据库. realm 整体的优点有这么四点: ...

  3. ASP.NET Core Windows 环境配置

    ASP.NET Core 是对 ASP.NET 有重大意义的一次重新设计.本章节我们将介绍 ASP.NET Core 中的一些新的概念和它们是如何帮助我们开发现代化的 Web 应用程序 尽管 ASP. ...

  4. [LeetCode] 565. Array Nesting 数组嵌套

    A zero-indexed array A of length N contains all integers from 0 to N-1. Find and return the longest ...

  5. [LeetCode] 410. Split Array Largest Sum 分割数组的最大值

    Given an array which consists of non-negative integers and an integer m, you can split the array int ...

  6. 第21课 shared_ptr共享型智能指针

    一. shared_ptr的基本用法 (一)与unique_ptr的比较 比较 shared_ptr unique_ptr 备注 初始化 ①shared_ptr<T> sp; sp.res ...

  7. 在 QML 中使用 C++ 类和对象

    Qt Quick 技术的引入,使得你能够快速构建 UI ,具有动画.各种绚丽效果的 UI 都不在话下.但它不是万能的,也有很多局限性,原来 Qt 的一些技术,比如低阶的网络编程如 QTcpSocket ...

  8. 创建简单Maven项目

    目录: Maven基础构建概念.仓库.构建与部署 Maven作用 Maven项目install Maven安装配置.目录结构.配置文件 配置Maven默认本地仓库 Maven常见命令 使用Maven ...

  9. 前端与算法 leetcode 387. 字符串中的第一个唯一字符

    目录 # 前端与算法 leetcode 387. 字符串中的第一个唯一字符 题目描述 概要 提示 解析 解法一:双循环 解法二:Set法单循环 算法 传入测试用例的运行结果 执行结果 GitHub仓库 ...

  10. SpringBoot整合mybatis及注意事项

    SpringBoot整合mybatis及注意事项 主要步骤 添加依赖 mybatis 在配置文件中配置数据源信息 编写pojo mapper接口 mapeer映射文件 手动配置mybatis的包扫描 ...