创建文件到底发生了什么?

为什么要浅浅探究这个问题?

大家大部分时间的工作其实都是写业务层的”CURD“,而真正陪伴在我们身边的计算机底层原理则不再有那么多好奇心去探究了。这篇文章旨在抛砖引玉,也许大家在空闲的时间里,也能够去探求自己以前一直想知道的原理到底是怎么样的。
如何探究?
这里是使用了自顶向下的方式去探寻。说人话就是从业务层代码入手,逐层探讨,不说废话,直接进入正片部分。

分层:

Java层:

这里放一段简单的创建文件的kotlin代码:
在这里插入图片描述
从理论上来讲,Java本身是在JVM上面运行的,我们的Java层代码是不可能直接利用操作系统中文件系统相关的系统调用来创建文件的。
那么这里要探究的是createNewFile这个方法往下走发生了什么?
File.java:
在这里插入图片描述
这里说明调用了一个Java层的文件系统方法来创建文件。
UnixFileSystem.java:继承自FileSystem抽象类在这里插入图片描述
可以看到,这里确实有一个native方法,说明这个事情是在JDK内的c++底层代码做的。

c++层:

结合JNI和JAVACPP,知道了Java调用CPP代码的文件规则和函数映射规则,所以我们可以很快的从JDK8的源码里面找到对应的native方法在哪里。就在UnixFileSystem_md.c中。
顺利找到了native的表层实现:
在这里插入图片描述
这里插入解释一下几个参数的意思:
第一个参数:path是文件路径
第二个参数:希望做的操作,这里用or标识符说明是希望串行一起做。这里还有很多定义好的枚举,因为不是本文重点,这里不再罗列,感兴趣可以自己搜索学习。比如这里就是想执行:读写or创建or取消(如果失败就继续创建下去的执行链),所以在这里就知道了,当一个路径文件已经存在的时候,就不会再创建了,因为在尝试读写的时候就已经成功了,不会再走创建流程。(会先尝试读写,读写失败再创建)
第三个参数:0666是文件开放权限的编码。会发现这是以0开头的数字,在c语言体系中0开头说明是八进制。
为什么是八进制?这里就跟文件系统的权限分配有关系了,这里简单说明一下:
1.八进制转化为二进制是三位,比如000。众所周知每一个二进制位都可以在约定下携带一个或者一类信息,那么这里是三个八进制数也就可以携带9个信息,那么具体是哪9个信息?
2.第一个八进制代表文件所有者的权限、第二个八进制代表文件用户组的权限、第三个八进制代表其他用户的权限。相当于是对用户权限作管理
3.而八进制内部,则对具体的权限划分作了划分,首先定义文件基本的三种权限:可读、可写、可执行。正好对应三位(我想,设计为八进制也是因为这个)。从高到低以此,赋值为1说明是允许的
那么回过头来看这个0666,就知道是什么意思了,说明无论是哪个用户,都对该文件有可读和可写的权限。这也解答了为什么我用代码创建一个文件后,所有用户都可以任意访问操作的问题了。
表现到我们能看到的命令行界面就是,我们输入ls -l后,会显示在最前面的权限分配情况:
比如这个dubbo堆栈文件,就说明他的权限编码是0644
在这里插入图片描述
再往下就需要我们知道handleOpen做了什么事情:
在这里插入图片描述

可以看到核心就是这个open64函数。(RESTARTBLE函数的作用只是重试而已,本身不跟操作系统交互)
下面的fstat只是为了拿到一些已创建文件的信息而已,也不是研究的重点。

open64函数本身就已经是UNIX系统调用最上层暴露给程序员调用的接口(即系统调用),如果还想往下,就到了系统内核层了。
这里补充一个系统调用的概念:一个完整的系统调用由三部分组成———(1.系统调用参数、2.系统调用执行、3.恢复原程序现场)

这里插一段open函数反汇编的汇编语言,其实大概就知道操作系统做了什么事情了。这里的汇编是ARM汇编。
汇编语言类型涉及到了CPU架构和指令集的区别。主要分为CISC(复杂指令系统计算机)和RISC(精简指令系统计算机)。ARM架构属于RISC主要用于移动端,而我们常用的英特尔、奔腾一般使用X86架构,主要用于PC。我们录播主机应该用的就是X86的架构。
这里可以发现,在libc_open函数中,就会有系统调用痕迹,open系统调用号为5(哪里来的?一般都是计算机架构设计的时候约定的)。
并且也可以发现,系统调用是会触发中断的,这就跟操作系统的执行方式有关系了,只有用户级代码是可以直接执行的,像系统调用这种内核级的命令,是需要触发中断,通知操作系统去执行这一段系统调用程序后,再重新回到原来的用户级代码中执行的。

000082f0 <main>:82f0:	e92d4800 	push	{fp, lr}82f4:	e28db004 	add	fp, sp, #4	; 0x482f8:	e24dd010 	sub	sp, sp, #16	; 0x1082fc:	ebffffd5 	bl	8258 <test>8300:	e1a03000 	mov	r3, r08304:	e50b300c 	str	r3, [fp, #-12]8308:	e59f002c 	ldr	r0, [pc, #44]	; 833c <main+0x4c>830c:	e3a01002 	mov	r1, #2	; 0x28310:	eb002e82 	bl	13d20 <__libc_open> //进入文件操作核心方法8314:	e1a03000 	mov	r3, r08318:	e50b3008 	str	r3, [fp, #-8]831c:	e59f301c 	ldr	r3, [pc, #28]	; 8340 <main+0x50>00013d20 <__libc_open>:13d20:	e51fc028 	ldr	ip, [pc, #-40]	; 13d00 <___fxstat64+0x50>13d24:	e79fc00c 	ldr	ip, [pc, ip]13d28:	e33c0000 	teq	ip, #0	; 0x013d2c:	1a000006 	bne	13d4c <__libc_open+0x2c>13d30:	e1a0c007 	mov	ip, r7  //把r7原来的数据暂存到ip寄存器13d34:	e3a07005 	mov	r7, #5	; 0x5    //open的系统调用号513d38:	ef000000 	svc	0x00000000   //产生软中断13d3c:	e1a0700c 	mov	r7, ip  //这里是系统中断后回复现场的代码,说白话就是把ip寄存器本来存的东西还给r7寄存器13d40:	e3700a01 	cmn	r0, #4096	; 0x100013d44:	312fff1e 	bxcc	lr13d48:	ea0008b0 	b	16010 <__syscall_error>

操作系统层(系统内核):

由于不同操作系统的实现是不同的,这里不对多个操作系统都进行的探讨,仅以linux系统为例分析,因为linux的源码比较好找到。
open函数的宏定义,可以看到,实际上调用的是do_sys_open函数,这才是真正系统调用的函数。
open.c:
在这里插入图片描述

在这里开始执行系统调用,具体的系统调用过程这里不会再展开讨论了。
感兴趣的话有机会可以再重点展开一下,这里再往下会涉及Linux内核操作系统的详细设计,包括文件系统设计、权限设计、安全设计,会很庞大。
这里基本上就是最难啃的一部分了,但至少我们已经摸到内核层了,在之前的流程都能梳理的比较清楚了。
在这里插入图片描述在这里插入图片描述

流程梳理:

基本流程很简洁,其实就是一个三层调用结构而已。
在这里插入图片描述

怎样跟踪系统调用的情况?

从代码层知道了大致的原理,那么如果我想在我的电脑上去跟踪系统调用怎么办?比如我就想知道,我开始执行一行创建文件的Java代码发生了什么,我想知道操作系统做这件事有没有痕迹或记录,怎么办?
很多人由于好奇心或者工作,都有这方面的需要。市面上也有很多跟踪系统调用的工具,很多操作系统本身自带有跟踪命令。这里以Linux系统为例。(MACOS有自己的dtruss和dtrace工具,但是一般都会被安全策略禁用,感兴趣可以自己尝试一下)
介绍一个跟踪命令:strace
strace作为老牌Linux系统调用跟踪工具,是一定要介绍一下的。其他的工具如perf等,可以自己查资料学习。
常用的命令如:strace -e trace=<系统调用名称1>,<系统调用名称2>… -p
解释一下:就是跟踪这个进程上会发生的指定的系统调用集合是怎么样的。
这里用我们自己的服务器抓一下就好了。我这里抓的是进程pid是1,可以理解成我抓的是操作系统全局的系统调用。
在这里插入图片描述

该命令会将系统调用的参数和返回值都打印出来。在Linux中返回值为13说明系统调用成功,反之则是异常情况,需要进行排查。
上面这一段给了我们什么信息呢?
1.我们可以知道,这些系统调用都成功了,如果失败了我们可以以此为依据分析原因。
2.我们窥探到了操作系统到底每天在干什么事情,从这些路径我们可以看出,操作系统需要频繁访问这些文件。这都是些什么文件?比如第一个是磁盘挂载文件信息文件、第二个是PCI通信数据文件、第三个是设备相关标识文件。自此,我们从只能看到简单的CRUD代码,终于能够知道每天在用的操作系统到底在干什么事情的冰山一角了。

意义:

1.终于知道从Java层走到操作系统层,大概发生了什么,尽管还没有全局了解,但已经实现了从0-1过程,之后无论是探求网络socket链接、nio实现等,都知道大概是怎么走到最底层的了。
2.学会了简单的跟踪系统调用,说明系统调用跟踪本身并没有什么难度,只要知道原理和掌握工具,不是什么不可触及的领域。
3.觉得有意思本身就是意义

相关资料:

JDK8源码:https://github.com/openjdk/jdk/blob/master/src/
相关Linux开源内核源码:https://github.com/raspberrypi/linux/

记一篇失踪博主的不定时回归文章吧,daze☆

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

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

相关文章

AcWing最长连续不重复子序列

哈希表就完事儿了&#xff0c;key是a[j],value是a[j]出现次数 i丢到前面&#xff0c;j丢到后面&#xff0c;然后j往后面遍历&#xff0c;每次记录a[j]出现次数 m a p [ a [ j ] ] map[a[j]] map[a[j]]&#xff0c;如果a[j]出现次数2次及其以上 m a p [ a [ j ] ] > 1 map[a[…

信号量的实例

例题&#xff1a; 进程 a 和进程 b 模拟访问打印机&#xff0c;进程 a 输出第一个字符‘ a’表示开始使用打印 机&#xff0c;输出第二个字符‘ a’表示结束使用&#xff0c; b 进程操作与 a 进程相同。&#xff08;由于打印机同一时刻 只能被一个进程使用&#xff0c;所以输出…

【数据结构--排序】

目录 一、排序概述1.1、排序的相关定义1.2、排序用到的结构与函数 二、常见排序算法2.1、冒泡算法&#xff08;交换顺序&#xff09;&#xff08;1&#xff09;算法&#xff08;2&#xff09;性能分析 2.2、简单选择排序&#xff08;1&#xff09;算法&#xff08;2&#xff09…

yolov5-7环境搭建训练自己的模型

1.下载代码 git clone https://github.com/ultralytics/yolov5 # clone可以切到5-7版本&#xff0c;也可以去github选标签下载 2.配置好conda环境&#xff0c;网上教程比较多&#xff0c;不做讲解&#xff0c;python3.8即可。 3.在环境里安装pyrtorch 按自己的需求选取&am…

C#初级——条件判断语句、循环语句和运算符

条件判断语句 简单的条件判断语句&#xff0c;if()里面进行条件判断&#xff0c;如果条件判断正确就执行语句块1&#xff0c;如果不符合就执行语句块2。 if (条件判断) { 语句块1 } else { 语句块2 } int age 18;if (age < 18){Console.WriteLine("未…

『 Linux 』信号的捕捉及部分子问题

文章目录 信号的捕捉sigaction函数未决信号集的置零时机信号处理过程的阻塞可重入函数volatile 关键字SIGCHLD 信号 信号的捕捉 该图为基于信号处理为用户自定义动作的图解; 信号的捕捉 当一个信号被递达时,如果该信号的处理动作是用户自定义的函数(如int sighandler(int))时就…

钉钉 钉钉打卡 钉钉定位 2024 免费试用 保用

打卡助手定位 如图&#xff0c;表示开启成功&#xff0c;软件已定位到钉钉打卡位置。 测试显示&#xff0c;高德地图位置已成功修改。 开启助手定位后&#xff0c;观察效果&#xff0c;打卡按钮由无法打卡变为可打卡状态&#xff0c;照片还显示打卡地点。 伙伴们担心作弊行为会…

Prometheus Pushgateway 协议上报观测云最佳实践

Pushgateway 介绍 Pushgateway 是 Prometheus 生态系统中的一个组件&#xff0c;主要用于解决 Prometheus 默认的 pull&#xff08;拉取&#xff09;模式在某些情况下无法获取数据的问题&#xff0c;如监控源位于防火墙之后&#xff0c;Prometheus 无法穿透防火墙&#xff0c;…

嵌入式C++、Raspberry Pi、LoRa和Wi-Fi技术、TensorFlow、ROS/ROS2:农业巡检数据导航机器人设计流程(代码示例)

随着科技的不断进步&#xff0c;农业领域也在逐渐向智能化发展。农业巡检机器人作为农业智能化的重要组成部分&#xff0c;能够自动化地监测农作物生长状况&#xff0c;提高农业管理的效率和精确度。本文将介绍一个基于Raspberry Pi和NVIDIA Jetson的农业巡检机器人&#xff0c…

3U/6U CPCI 系统核心模块,可应用于电力、轨道交通等领域

一、3U CPCI核心模块 提供CPCI系列产品&#xff0c;具有&#xff0c;高性能&#xff0c;应用扩展灵活&#xff0c;X86软件兼容&#xff0c;无风扇设计&#xff0c;宽工作温度范围&#xff0c;长嵌入式生命周期等特点&#xff0c;满足不同客户的需求。 产品特点 Intel Pentium …

微信Android一面凉经(2024)

微信Android一面凉经(2024) 笔者作为一名双非二本毕业7年老Android, 最近面试了不少公司, 目前已告一段落, 整理一下各家的面试问题, 打算陆续发布出来, 供有缘人参考。今天给大家带来的是《微信Android一面凉经(2024)》。 面试职位: 微信-客户端开发工程师-基础功能(广州) And…

力扣高频SQL 50 题(基础版)第四题

文章目录 力扣高频SQL 50 题&#xff08;基础版&#xff09;第四题584.寻找用户推荐人题目说明思路分析实现过程准备数据实现方式结果截图 力扣高频SQL 50 题&#xff08;基础版&#xff09;第四题 584.寻找用户推荐人 题目说明 表: Customer -------------------- | Colu…

【Code Complete2】Note-1 [启发式编程、管理复杂度、隐藏设计]

【Code Complete2】_Note-1 [启发式编程、管理复杂度、隐藏设计] 文章目录 【Code Complete2】_Note-1 [启发式编程、管理复杂度、隐藏设计]启发式编程管理复杂度隐藏设计--减少“改动所影响的代码量” 启发式编程 ​ **设计是一个启发的过程&#xff0c;充满了不确定性&#…

Golang | Leetcode Golang题解之第283题移动零

题目&#xff1a; 题解&#xff1a; func moveZeroes(nums []int) {left, right, n : 0, 0, len(nums)for right < n {if nums[right] ! 0 {nums[left], nums[right] nums[right], nums[left]left}right} }

Anaconda +Pytorch安装教程

Anaconda Pytorch安装教程 Anaconda安装 小土堆的安装教程&#xff1a;PyTorch深度学习快速入门教程&#xff08;绝对通俗易懂&#xff01;&#xff09;【小土堆】_哔哩哔哩_bilibili Free Download | Anaconda 这里自己选一个文件夹安装即可 第一个红框表示添加图标到开始菜…

pytorch-scheduler(调度器)

scheduler简介 scheduler(调度器)是一种用于调整优化算法中学习率的机制。学习率是控制模型参数更新幅度的关键超参数,而调度器根据预定的策略在训练过程中动态地调整学习率。 优化器负责根据损失函数的梯度更新模型的参数,而调度器则负责调整优化过程中使用的特定参数,通…

【C++笔试强训】day03

简写单词 思路 首先把第一个字符&#xff08;转大写&#xff09;加到答案t中。 遍历字符串s的同时&#xff0c;如果遇到了空格&#xff0c;就把空格后面的字符&#xff08;转大写&#xff09;加到t中。 代码 #include <bits/stdc.h>using namespace std;int main() {…

The conversion of the nvarchar value ‘10033121171441‘ overflowed an int column

The conversion of the nvarchar value ‘10033121171441‘ overflowed an int column 目录 The conversion of the nvarchar value ‘10033121171441‘ overflowed an int column 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎…

Linux冯诺依曼体系、操作系统、进程概念、进程状态、进程切换

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;Linux 目录 一、冯诺依曼体系结构 二、操作系统 1、概念 2、为什么要有操作系统&#xff1f; 3、理解操作系统 1.管理的本质 2.管理的概念 3.操作系统结构图 4.为什么要有操作系统&#xff1f; 三…

扁平化Tree组件Vue3过渡动画

本小节在巧用Vue3 composition api的计算属性实现扁平化tree连线 的基础上实现动画效果。 看下目前的实现&#xff0c;展开折叠比较生硬&#xff0c;正好我们用vue提供的过渡动画特性来优化用户体验。 模板应用动画 在for循环渲染外面应用过渡组标签&#xff0c;对每个节点的…