1. 硬链接和软连接区别
硬连接-------指通过索引节点来进行连接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)。在Linux中,多个文件名指向同一索引节点是存在的。比如:A是B的硬链接(A和B都是文件名),则A的目录项中的inode节点号与B的目录项中的inode节点号相同,即一个inode节点对应两个不同的文件名,两个文件名指向同一个inode节点,A和B对文件系统来说是完全平等的。删除其中任何一个都不会影响另外一个的访问。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除,如果我们删除硬链接文件的源文件,硬链接文件仍然存在,而且保留了原有的内容。
软链接--------又叫符号链接,有点类似于Windows的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。比如:A是B的软链接(A和B都是文件名),A的目录项中的inode节点号与B的目录项中的inode节点号不相同,A和B指向的是两个不同的inode,继而指向两块不同的数据块。但是A的数据块中存放的只是B的路径名(可以根据这个找到B的目录项)。A和B之间是“主从”关系,如果B被删除了,A仍然存在(因为两个是不同的文件),但指向的是一个无效的链接。
附加: linux系统下的文件包括inode结构和data两部分,其中inode结构中有两个引用计数icount和inlink,前者记录该文件当前的使用者数量,后者记录该文件的介质链接数量,即前者针对内存,后者针对硬盘,只有这两个引用计数值都为0的情况下,data的删除才真正进行。
2. kill用法,某个进程杀不掉的原因(进入内核态,忽略kill信号)
(1)kill用法
先用查看进程id命令 ps -ef , 然后用杀死进程 kill -9 PID
(2).进程杀不掉的原因:
(1)进程已经成为僵尸进程,当它的父进程将它回收或将它的父进程kill掉,此时进程已经释放所有的资源,但是没有被父进程释放(所以僵尸进程的存在不会影响系统性能)。僵尸进程要等到父进程结束,或者重启系统才可以被释放。
(2)进程正处在内核状态中,Linux进程运行时分内核和用户两种状态,当进程进入内核状态后,会屏蔽所有信号,包括SIGKIL,所以这个时候kill -9也变得无效了。
3.系统管理命令(如查看内存使用、网络情况)
(1) df 和 df -hl 用来检查文件系统的磁盘空间占用情况,使用权限是所有用户
(2) top, top命令用来显示执行中的程序进程,使用权限是所有用户(想对进程进行实时监控应该用top命令)
(3) free, free命令用来显示内存的使用情况,使用权限是所有用户
(4) lp, lp是打印文件的命令,使用权限是所有用户
(5) useradd, useradd命令用来建立用户帐号和创建用户的起始目录,使用权限是超级用户
(6) kill 杀死进程
(7)ps -ef 查看进程完整信息(PS显示的是进程瞬间状态,不连续) ps -aux列出目前所有正在内存中的进程信息
(8)netstat 查看网络状态
4.管道命令 |
管道命令操作符是:”|”,它只能处理经由前面一个指令传出的正确输出信息,对错误信息信息没有直接处理能力。然后,传递给下一个命令,作为标准的输入.
举例: logcat | grep "wakeupcount"
5. grep的使用,一定要掌握,每次都会问在文件中查找
grep - [ option ]
-c:仅仅输出匹配行的计数。
-I:不区分大 小写(仅仅适用于单字符)。
-h:查询多文件时不显示文件名称。
-l:查询多文件时仅仅输出包括匹配字符的文件名称。
-n:显示匹配行及 行号。
-s:不显示不存在或无匹配文本的错误信息。
-v:显示不包括匹配文本的全部行。
6. find命令
在/home目录下查找以.txt结尾的文件名: find /home -name "*.txt"
在/home目录下查找以.txt结尾的文件名,忽略大小写: find /home -iname "*.txt"
匹配文件路径或者文件: find /usr/-path"*local*"
基于正则表达式匹配文件路径: find .-regex".*\(\.txt\|\.pdf\)$"
7. awk使用
(1) 使用方法
awk '{pattern + action}' {filenames}
尽管操作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。 pattern就是要表示的正则表达式,用斜杠括起来。
awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本文件中的信息。
通常,awk是以文件的一行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本。
(2) 调用awk方法
1).命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。
2).shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用, ./shell_awk.sh 直接执行
相当于shell脚本首行的:#!/bin/sh 要换成:#!/bin/awk
3).将所有的awk命令输入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f 选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。
8. linux内核中的Timer 定时器机制
定时器是Linux提供的一种定时服务的机制。它在某个特定的时间唤醒某个进程,来做一些工作。系统定时器能以可编程的频率中断处理,这一中断叫做软中断。此频率即为每秒的定时器节拍数HZ。HZ的越大,说明定时器节拍越小,线程调度的准确性会越高。但HZ设得过大,对一个系统来说并不好,会导CPU开销过大,反而造成任务调度效率降低。jiffies 变量记录系统启动以来,系统定时器已经触发的次数。也就是说每过一秒jiffies的增量为HZ
9. 使用过的 shell 命令
cp , mv , rm , mkdir , touch , pwd , cd , ls , top , cat , tail , less , df , du , man , find , kill , sudo , cat
10. 使用过的 vim 命令
wq!, dd , dw , yy , p , i , %s/old/new/g , /abc 向后搜索字符串abc , ?abc向前搜索字符串abc
11. gdb
一. gdb命令
(1)启动gdb 的命令 gdb a.out (2)获得帮助命令 (gdb)help
(3) 查看程序源代码 (gdb) list (4)从文件头部向尾部搜索源代码 (gdb) search 要匹配的代码
(5)设置断点 (gdb)b / break 行数 (6)清除当前所在行的断点 (gdb) clear
(7)从头运行程序至第一个断点 (gdb) r / run
(8) 单步执行(遇到函数调用的时候不会进入函数体内部) (gdb) n/next
(9) 单步执行(遇到函数调用的时候会进入函数体内部) (gdb) s / step
(10)从当前行继续运行程序至下一个断点 (gdb)continue
(11)退出gdb (gdb) quit
二. gdb如何传参数?gdb怎么调试?
gdb调试 linux下如何使用gdb调试 - bu_想 - 博客园
(1)在使用gdb调试C/C++程序前,需要用gcc -g test.c -o test(-g选项告诉gcc在编译程序时加入调试信息,-o选项用来生成输出的文件名,没有-o选项的话就默认输出a.out文件名,有的话就输出我们自己设的test,但是自己设的文件名不能和原文件名一样) 命令生成带有调试信息的可执行程序,否则看到的将是一堆汇编代码。比如这个命令生成的是 test文件(如果不加-o选项生成的就是 a.out 文件)。
(2)接下来可以这样进入测试:gdb -q a.out (加上-q选项去除输出来的gdb的一些版本信息说明之类说明)
(3)使用(gdb)list 来查看程序的源代码,着通常是调试程序要做的第一件事情;list只能按顺序给出程序源代码,但是这样其实有时候不方便,为了定位到某条特定的语句,可以使用 (gdb) search +要找的代码
感觉第6行代码可能有点问题,现在就需要我就需要设置一个断点,让程序停在第6行之前。
想看下设置的断点信息,可以使用(gdb)info breakpoints命令。
如果不需要断点了,可以用(gdb)disable 1 (1是断点的编号,不是行号)使得断点失效
或者(gdb) clear 1 直接删除该断点1。(如果没有断点编号参数的话,就是删除当前行的断点)
如果 (gdb)delete 则删除全部断点
(4)用 (gdb)run 开始运行;
用(gdb)n / next 单步执行(遇到函数调用的时候不会进入函数体内部), 用(gdb) s / step遇到函数调用的时候会进入函数体内部) ;
用(gdb)continue 指导gdb从当前行继续运行至下一个断点
(5)用 (gdb)quit 退出gdb调试;
12. gcc常用选项总结
(1)常规选项:
-o选项,(小o)指定输出文件名 -c选项,只编译,不汇编连接
-S选项,产生汇编源文件 -E选项,预处理C源文件
(2)优化选项
-O选项,基本优化 -O2选项,最大优化
(3)调试选项
-g选项,产生供gdb调试用的可执行文件 -pg选项,产生供gprof剖析用的可执行文件
13. I/O多路复用之---------select、poll和epoll
select: IO多路复用之select总结 - Anker's Blog - 博客园
poll: IO多路复用之poll总结 - Anker's Blog - 博客园
epoll: IO多路复用之epoll总结 - Anker's Blog - 博客园
I/O多路复用:I/O多路复用就通过一种机制,可以监视多个文件描述符,一旦某个描述文件符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
基本思想是:先构造一张有关文件描述符的表,然后调用相应函数,当这些文件描述符中的一个或多个已经准备好进行I/O时函数才返回,函数返回时告诉进程哪个描述符已经就绪可以进行I/O操作了。
IO多路复用适用如下场合:
(1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。
(2)当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。
(3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。
(4)如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。
(5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。
与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。
(1)select: I/O多路复用之select - zengzy - 博客园
select: 允许进程监听多个文件描述符组成的一个集合,它会一直阻塞等待,直到集合中有一个或多个文件描述符(或者说资源)准备就绪,那么函数会立刻返回并告诉进程哪个文件描述符已经准备好了。(注意:select 函数执行完毕后,会清除掉集合中没有准备就绪的文件描述符)
具体解释来说就是-----------当应用程序调用select() 函数, 内核就会相应调用 poll_wait(), 把当前应用程序进程添加到相应设备的等待队列上,然后将该应用程序进程设置为睡眠状态。直到该设备上的数据可以获取,然后调用wake_up()唤醒该应用程序进程。select每次轮询都会遍历所有文件描述符fd。
select本质上是通过设置或者检查存放fd标志位(fd就是文件描述符file descriptor)的数据结构来进行下一步处理。它通过一个select()系统调用来监视多个文件描述符的数组;
这样所带来的缺点是:
1)、 单个进程可监视的fd数量被限制(可监听的fd数量为maxfd),即能监听端口的大小有限。
一般来说这个数目和系统内存关系很大,具体数目可以cat /proc/sys/fs/file-max察看。32位机默认是1024个。64位机默认是2048.
2)、 对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低:
当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,那就避免了轮询,这正是epoll与kqueue做的。
3)、需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大
( 注释:再强调一下fd标志位,每个进程的结构里面有一个列表,这个列表包含了进程中所有被打开的文件(socket也是文件的一种)的信息。列表里面每一个文件占用一个槽,而fd就是指的该文件槽的位置。一般来说进程中手工打开文件时第一个fd 为 3, 而0,1,2 都是被系统使用的。其中 0 是 stdin,也就是标准输入,例如从键盘输入或者unix下面的pipe。1是stdout,也就是标准输出,一般来说是屏幕,如果有管道的话就发到管道里面, 2是stderr,就是错误输出。)
Linux环境编程之文件I/O(一):文件描述符 - 小贱6 - 博客园
文件描述符:内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。文件描述符在形式上是一个非负整数。实际上,它是一个索引值(可以理解为数组下标),指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。当我们想要用read、write等系统调用对文件进行读写等操作之前,必须用open或create系统调用得到文件的描述符。
文件描述表:每个进程在Linux内核中都有一个task_struct结构体(就是PCB)来维护进程的相关信息,称为进程描述符。PCB中有文件描述符表(有个指针成员(struct files_struct *files)指向files_struct结构体),文件描述符表是个数组结构,其中的每个表项包含一个指向已打开的文件的指针(可以理解为数组里面存的是指针)。用户不能直接访问内核中的文件描述符表,而只能使用文件描述符表的索引(即数组下标0,1,2,3.......),即文件描述符。
文件描述符、文件指针、文件路径三者之间的关系:
(1)首先,文件描述符fd一般是在Unix系统或类Unix系统中的概念,它其实是一个整数,用它可以来获取文件描述符表中的某个已打开文件。
(2)文件指针FILE是C库中的概念,它不单单在Linux系统中,在windows中也会出现,文件指针指向进程中用户区中一个被称为FILE结构的数据结构,该FILE结构包括一个缓冲区和一个文件描述符。FILE中包含fd信息,还包含IO缓冲,所以FILE比fd更适合跨平台。它们之间可以利用fdopen函数和fileno函数互相转化。
FILE *fdopen(int fd, const char *mode);
int fileno(FILE *stream);
(3)文件路径就是文件所在路径,通常,我们就是通过文件路径得到具体文件,从而得到文件描述符、文件指针的。
(2)poll:
poll本质上和select没有区别,它将用户传入的文件描述符表拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中将该进程加入,并继续遍历;如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时该进程才再次被唤醒,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。
在select/poll时代,服务器进程每次都把这100万个连接告诉操作系统(从用户态复制句柄数据结构到内核态),让操作系统内核去查询这些套接字上是否有事件发生,轮询完后,再将句柄数据复制到用户态,让服务器应用程序轮询处理已发生的网络事件,这一过程资源消耗较大,因此,select/poll一般只能处理几千的并发连接。
它没有最大连接数的限制,原因是它是基于链表来存储的,但是同样有一个缺点:
1、大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。
2、poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。
(3)epoll:
它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入就绪链表的描述符集合就行了
与select相比,epoll分清了频繁调用和不频繁调用的操作。例如,epoll_ctrl是不太频繁调用的,而epoll_wait是非常频繁调用的。这时,epoll_wait却几乎没有入参,这比select的效率高出一大截,而且,它也不会随着并发连接的增加使得入参越发多起来,导致内核执行效率下降。
epoll有EPOLLLT和EPOLLET两种触发模式,LT是默认的模式,ET是“高速”模式。
(4)epoll为什么要有EPOLLET (ET) 触发模式?彻底学会使用epoll(一)——ET模式实现分析-lvyilong316-ChinaUnix博客
如果采用EPOLLLT (LT) 模式的话,系统中一旦有大量你不需要读写的就绪文件描述符,这些就绪文件描述符都会被放入到ready list中去,每次调用epoll_wait都会返回 fd 并通知给用户空间; 这样会大大降低处理程序检索自己关心的就绪文件描述符的效率.。而采用EPOLLET这种边沿触发模式的话,当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会返回并通知进程,也就是它只会通知一次,直到该文件描述符上出现第二次可读写事件才会返回fd并通知进程!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符
(5)epoll的优点:
1、没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口);
2、效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;
即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。
3、另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入rdlist就绪链表中的描述符集合就行了
4、 内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销。
(6)select、poll、epoll 区别总结:(最重要的)
select、poll、epoll之间的区别总结[整理] - Anker's Blog - 博客园
1)支持一个进程所能打开的最大连接数
select:单个进程所能打开的最大连接数有FD_SETSIZE宏定义,其大小是32个整数的大小(在32位的机器上,大小就是3232,同理64位机器上FD_SETSIZE为3264),当然我们可以对进行修改,然后重新编译内核,但是性能可能会受到影响,这需要进一步的测试。
poll:poll本质上和select没有区别,但是它没有最大连接数的限制,原因是它是基于链表来存储的
epoll:虽然连接数有上限,但是很大,1G内存的机器上可以打开10万左右的连接,2G内存的机器可以打开20万左右的连接
2)FD剧增后带来的IO效率问题
select:因为每次调用时都会对连接进行线性遍历,所以随着FD的增加会造成遍历速度慢的“线性下降性能问题”。
poll:同上
epoll:因为epoll内核中实现是根据每个fd上的callback函数来实现的,只有活跃的socket才会主动调用callback,所以在活跃socket较少的情况下,使用epoll没有前面两者的线性下降的性能问题,但是所有socket都很活跃的情况下,可能会有性能问题。
3) 消息传递方式
select:内核需要将消息传递到用户空间,都需要内核拷贝动作
poll:同上
epoll:epoll通过内核和用户空间共享一块内存来实现的。
总结:
综上,在选择select,poll,epoll时要根据具体的使用场合以及这三种方式的自身特点。
1、表面上看epoll的性能最好,但是在连接数少并且连接都十分活跃的情况下,select和poll的性能可能比epoll好,毕竟epoll的通知机制需要很多函数回调。
2、select低效是因为每次它都需要轮询。但低效也是相对的,视情况而定,也可通过良好的设计改善
14. Linux内存管理
主要是三个方面: 虚拟内存管理 内核空间内存管理 用户空间内存管理
(1)Linux下,物理内存的管理是按区划分的,一般来说32位系统的内存可以分为:
ZONE_DMA 低于16M的内存(用于DMA访问(直接内存访问))
ZONE_NORMAL 高于16M低于896M的内存
ZONE_HIGHMEM 高于896M的内存 (通常称之为高端内存)
前面已经提到,低于896M的内存和虚拟内存是线性映射的,内核可以直接访问到,而ZONE_HIGHMEM则需要调用特定的接口动态映射使用。
在64位的系统下,由于虚拟地址空间远远大于可安装的物理内存,因此,64位下的ZONE_HIGHMEM总是空的。
高端内存的使用(Linux内存管理-高端内存(一) - Jessica程序猿 - 博客园),可以通过三种机制来映射使用,分别映射到 内核动态映射空间, 永久内核映射,临时内核映射
(2)linux对物理内存的管理主要还是体现在其分配和回收上。
这就要提到著名的伙伴系统算法了,接下来我们重点看下该算法为什么适用于linux下的内存管理。
对于内存这种频繁申请释放的资源,最大的问题应该是如何避免内存碎片问题。通常思路,为避免内存碎片的情况,可以有两种思路:
① 在分页时,使用非连续的空闲物理页映射到连续的线性地址空间
② 使用一种方式记录现存的空闲连续页的情况,尽量避免为满足小块内存的请求而分割连续的大空闲块
第一种思路在分配连续的物理内存时可能时常会遇到困难。同时,非连续的空闲物理页时常映射必然导致页表频繁的被修改,这样TLB(转换检测缓冲区:是一个内存管理单元,用于改进虚拟地址到物理地址转换速度的缓存)的命中率也会下降,对性能是有比较大的影响的。
因此,linux选择了第二种思路做为解决方案,在具体的算法上选择了业界比较成熟的伙伴系统算法。linux把所有的物理空闲页分成了11个块链表,每个块链表分别包含了大小1,2,4,8,16,32,64,128,256,512和1024个连续页框的页框块。最大可以申请1024个连续页框,对应4MB大小的连续内存。每个页框块的第一个页框的物理地址是该块大小的整数倍。例如,大小为16个页框的块,其起始地址是16*2^12(2^12=4096)的整数倍。
在伙伴算法的控制下,申请内存和释放内存块按照伙伴算法(选择合适大小的链表取内存块,如若没有合适大小的内存块,则从大小接近的链表中,合并或切分内存 伙伴算法原理及其简单实现)。释放内存过程则是逆过程,将释放的内存选择合适的链表并加入其中。具体伙伴算法的细节,大家可参考相关资料,这里不细表。
伙伴算法管理的内存管理的内存适合大块的内存,但如果对小内存管理,如几个几十几百个字节的空间。如直接给一个页则导致内存空间的浪费。linux针对小内存的管理,提供了另一个专门的分配器,slab分配器(【操作系统,进程,多线程】 - 简书 第12点里面)。linux的提供配置一组slab/slob/slub的选择,不同的分配器在不同的应用场景下有着不同的应用。我们这里简单的了解一下slab分配器的基本原理,slab分配器申请了一系列的连续物理内存,该内存保存在系统的高速缓存当中,当需要小内存从这些高速缓存中直接申请。slab分配器并不直接释放已分配的内容,而是等到系统的内核线程周期性的扫描高速缓存并释放slab的内容。
伙伴算法:
15. Linux写时拷贝技术(copy-on-write)
在linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,linux中引入了“写时复制”技术,也就是只有进程空间的各段的内容要发生变化时,才将父进程的内容复制一份给子进程。
那么子进程的物理空间没有代码,怎么去取指令执行exec系统调用呢??
在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,其对应的物理空间是一个。当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间。如果不是因为exec,内核会给子进程的数据段、堆栈段分配相应的物理空间(至此两者都有各自的进程空间,互不影响),而代码段继续共享父进程的物理空间(两者的代码完全相同)。而如果是因为exec,由于两者执行的代码不同,子进程的代码段也会分配单独的物理空间。
总结:
传统的fork()系统调用直接把所有的资源复制给新创建的进程。这种实现过于简单并且效率低下,因为它拷贝的数据也许并不共享,更糟的情况是,如果新进程打算立即执行一个新的映像,那么所有的拷贝将是无用功。
Linux的fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至免除拷贝数据的技术。内核此时并不复制整个地址空间,而是让父进程和子进程共享一个拷贝。只有在需要写入的时候,数据才会复制,从而使各个进程拥有各自的拷贝。也就是说,资源的复制只有在需要写入的时候才进行,在此之前,只是以只读方式共享。这种技术使地址空间的页的拷贝被推迟到实际发生写入的时候。
在页根本不会被写入的情况下,举例来说,fork()之后立即调用exec(),它们就无需复制了,fork()的实际开销就是复制父进程的页表以及给子进程创建唯一的进程描述符。在一般情况下,进程创建后都会马上运行一个可执行的文件,这种优化可以避免拷贝大量根本不会使用的数据(地址空间常常包含数十兆的数据)。由于Unix强调进程快速执行的能力,所以这个优化是很重要的,注:Linux COW和exec没有必然联系
16. Linux内核相关知识(内核结构)
内核主要是五个子系统组成------进程管理,进程间通信,内存管理,网络协议栈,虚拟文件系统
(1)PM(Procees Management 进程管理)------这一部分包括具体创建创建进程(fork、exec),停止进程(kill、exit),并控制他们之间的通信(signal等)。还包括进程调度,控制活动进程如何共享CPU。这一部分是Linux已经做好的,在写驱动的时候,只需要调用对应的函数即可实现这些功能,例如创建进程、进程通信等等。
(2)MM(Memory Management 内存管理)------内存管理的主要作用是控制多个进程安全的共享内存区域。
(3)IPC(Inter-Process Communication进程间通信)------IPC不管理任何的硬件,它主要负责Linux系统中进程之间的通信。
(4)Network Stack(网络协议栈)------ Linux内核中提供了丰富的网络协议实现。
(5)VFS(Virtual File Systems 虚拟文件系统)------虚拟文件系统,隐藏各种文件系统的具体细节,为文件操作提供统一的接口。在Linux中“一切皆文件”,这些文件就是通过VFS来实现的。Linux提供了一个大的通用模型,使这个模型包含了所有文件系统功能的集合。如下图所示,是一个虚拟文件系统的结构图:
17.Linux sort 、uniq、cut 命令详解
linux sort,uniq,cut,wc命令详解 - ggjucheng - 博客园
Sort:------- sort 命令对 File 参数指定的文件中的行排序,并将结果写到标准输出。如果 File 参数指定多个文件,那么 sort 命令将这些文件连接起来,并当作一个文件进行排序。(sort 是默认以第一个数据来排序,而且默认是以字符串形式来排序,所以由字母 a 开始升序排序)
uniq------uniq命令可以去除排序过的文件中的重复行,因此uniq经常和sort合用。也就是说,为了使uniq起作用,所有的重复行必须是相邻的。
cut------cut命令可以从一个文本文件或者文本流中提取文本列。
18. 管道的实现机制
管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条。管道的一端连接一个进程的输出。这个进程会向管道中放入信息。管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。一个缓冲区不需要很大一般为4K大小,它被设计成为环形的数据结构,以便管道可以被循环利用。当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另一端的进程取出信息。当两个进程都终结的时候,管道也自动消失
从原理上------管道利用fork机制建立,从而让两个进程可以连接到同一个PIPE上。最开始的时候,上面的两个箭头都连接在同一个进程Process 1上(连接在Process 1上的两个箭头)。当fork复制进程的时候,会将这两个连接也复制到新的进程(Process 2)。随后,每个进程关闭自己不需要的一个连接 (两个黑色的箭头被关闭; Process 1关闭从PIPE来的输入连接,Process2关闭输出到PIPE的连接),这样,剩下的红色连接就构成了如上图的PIPE。
实现细节:在 Linux 中,管道的实现并没有使用专门的数据结构,而是借助了文件系统的file结构和VFS的索引节点inode。通过将两个 file 结构指向同一个临时的 VFS 索引节点,而这个 VFS 索引节点又指向一个物理页面而实现的。
有两个 file 数据结构,但它们定义文件操作例程地址是不同的,其中一个是向管道中写入数据的例程地址,而另一个是从管道中读出数据的例程地址。这样,用户程序的系统调用仍然是通常的文件操作,而内核却利用这种抽象机制实现了管道这一特殊操作。
19. 介绍一下 makefiles 说说Makefile那些事儿 - CSDN博客
makefile就是一个文本文件,在Makefile文件中描述了整个工程所有文件的编译顺序、编译规则,它能够纪录文件的信息,决定在链接的时候需要重新编译哪些文件。Makefile 有自己的书写格式、关键字、函数。而且在Makefile中可以使用系统shell所提供的任何命令来完成想要的工作。Makefile(在其它的系统上可能是另外的文件名)在绝大多数的IDE 开发环境中都在使用,已经成为一种工程的编译方法。
Makefile包含五个部分:显示规则,隐式规则,变量定义,文件指示,注释
1)、显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
2)、隐式规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
3)、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
4)、文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
5)、注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“/#”。
最后,还值得一提的是,在Makefile中的命令,必须要以[Tab]键开始。
20.mmap介绍 认真分析mmap:是什么 为什么 怎么用 - 胡潇 - 博客园
mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。如下图所示:
作用:将磁盘文件的数据映射到内存进程空间中,用户修改内存就能修改磁盘文件。
常规文件操作为了提高读写效率和保护磁盘,使用了页缓存机制。这样造成读文件时需要先将文件页从磁盘拷贝到页缓存中,由于页缓存处在内核空间,不能被用户进程直接寻址,所以还需要将页缓存中数据页再次拷贝到内存对应的用户空间中。这样,通过了两次数据拷贝过程,才能完成进程对文件内容的获取任务。写操作也是一样,待写入的buffer页缓存在内核空间不能直接访问,必须要先拷贝至内核空间对应的主存,再写回磁盘中(延迟写回),也是需要两次数据拷贝。
而使用mmap操作文件中,创建新的虚拟内存区域,建立文件磁盘地址与虚拟内存区域映射这两步,没有任何文件拷贝操作。而之后访问数据时发现内存中并无数据而发起的缺页异常过程,可以通过已经建立好的映射关系,只使用一次数据拷贝,就从磁盘中将数据传入内存的用户空间中,供进程使用。
总而言之,常规文件操作需要从磁盘到页缓存再到用户内存的两次数据拷贝。而mmap操控文件,只需要从磁盘到用户内存的一次数据拷贝过程。说白了,mmap的关键点是实现了用户空间和内核空间的数据直接交互而省去了空间不同数据不通的繁琐过程。因此mmap效率更高。
mmap的优点
1)对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,用内存读写取代I/O读写,提高了文件读取效率。
2)实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉。
3)提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的。 同时,如果进程A和进程B都映射了区域C,当A第一次读取C时通过缺页从磁盘复制文件页到内存中;但当B再读C的相同页面时,虽然也会产生缺页异常,但是不再需要从磁盘中复制文件过来,而可直接使用已经保存在内存中的文件数据。
4)可用于实现高效的大规模数据传输。内存空间不足,是制约大数据操作的一个方面,解决方案往往是借助硬盘空间协助操作,补充内存的不足。但是进一步会造成大量的文件I/O操作,极大影响效率。这个问题可以通过mmap映射很好的解决。换句话说,但凡是需要用磁盘空间代替内存的时候,mmap都可以发挥其功效。
缺点: 使用相对麻烦,而且读写操作不会阻塞,可能会造成读写的快慢不同步,导致读写数据不完整。
21.Linux下的7种文件类型
22.Linux里的RCU 深入理解 Linux 的 RCU 机制 - 腾讯云+社区 - 博客园
RCU(Read-Copy Update),是 Linux 中比较重要的一种同步机制,称为:读拷贝更新机制,再直白点是“随意读,但更新数据的时候,需要先复制一份副本,在副本上完成修改,再一次性地替换旧数据”。这是 Linux 内核实现的一种针对“读多写少”的共享数据的同步机制。
不同于其他的同步机制,它允许多个读者同时访问共享数据,而且读者的性能不会受影响(“随意读”),读者与写者之间也不需要同步机制(但需要“复制后再写”),但如果存在多个写者时,在写者把更新后的“副本”覆盖到原数据时,写者与写者之间需要利用其他同步机制保证同步。
23 . cache缓存区和buffer缓冲区的理解
(1) Cache:缓存区,是高速缓存,是位于CPU和主内存之间的容量较小但速度很快的存储器,因为CPU的速度远远高于主内存的速度,CPU从内存中读取数据需等待很长的时间,而 Cache保存着CPU刚用过的数据或循环使用的部分数据,这时从Cache中读取数据会更快,减少了CPU等待的时间,提高了系统的性能。
Cache并不是用来缓存文件的,而是用来缓存 块 的( 块是I/O读写最小的单元);Cache一般会用在I/O请求上,如果多个进程要访问某个文件,可以把此文件读入Cache中,这样下一个进程获取CPU控制权并访问此文件直接从Cache读取,提高系统性能。
(2)Buffer:缓冲区,用于 存储速度不同步的设备 或 优先级不同的设备 之间传输数据;通过buffer可以减少进程间通信需要等待的时间,当存储速度快的设备与存储速度慢的设备进行通信时,存储慢的数据先把数据存放到buffer,达到一定程度存储快的设备再读取buffer的数据,在此期间存储快的设备CPU可以干其他的事情。
Buffer一般是用在写入磁盘的时候,例如:某个进程要求多个字段被读入,当所有要求的字段被读入之前已经读入的字段会先放到buffer中。
24. Linux支持的文件系统
Linux系统因为使用VFS,所有其核心可以支持如ext、ext2、ext3、ext4、JFS2等的多种的文件系统。下面说明其支持的几个重要的文件系统。
(1)ext-----专门为linux核心做的的第一个文件系统。单个文件最大限制:未知;该文件系统最大支持2GB的容量。
(2)ext2-----由Rémy Card设计,用以代替ext,是LINUX内核所用的文件系统。单个文件最大限制2TB;该文件系统最大支持32TB的容量。
(3)ext3-------一个日志文件系统。单个文件最大限制16TB,该文件系统最大支持32TB的容量。
(4)ext4-------Theodore Tso领导的开发团队实现,Linux系统下的日志文件系统。单个文件最大限制16TB,该文件系统最大支持1EB的容量。
(5)JFS2---------一种字节级日志文件系统,该文件系统主要是为满足服务器的高吞吐量和可靠性需求而设计、开发的。单个文件最大限制16TB,该文件系统最大支持1PB的容量。
25. shell里面$?,$$,$0,$#等代表什么意思?
26. wget命令 scp命令 rcp命令 wget命令 scp命令 rcp命令 - CSDN博客
(1)wget------Linux系统中的wget是一个下载文件的工具,它用在命令行下。对于Linux用户是必不可少的工具,我们经常要下载一些软件或从远程服务器恢复备份到本地服务器。wget支持HTTP,HTTPS和FTP协议,可以使用HTTP代理。所谓的自动下载是指,wget可以在用户退出系统的之后在后台执行。这意味这你可以登录系统,启动一个wget下载任务,然后退出系统,wget将在后台执行直到任务完成 。
wget 可以跟踪HTML页面上的链接依次下载来创建远程服务器的本地版本,完全重建原始站点的目录结构。这又常被称作”递归下载”。在递归下载的时候,wget 遵循Robot Exclusion标准(/robots.txt). wget可以在下载的同时,将链接转换成指向本地文件,以方便离线浏览。
(2)SCP------scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的。可能会稍微影响一下速度。当你服务器硬盘变为只读read only system时,用scp可以帮你把文件移出来。另外,scp还非常不占资源,不会提高多少系统负荷,在这一点上,rsync就远远不及它了。虽然 rsync比scp会快一点,但当小文件众多的情况下,rsync会导致硬盘I/O非常高,而scp基本不影响系统正常使用。
(3)rpc------rcp代表“remote file copy”(远程文件拷贝)。该命令用于在计算机之间拷贝文件。rcp命令有两种格式。
第一种格式用于文件到文件的拷贝;
第二种格式用于把文件或目录拷贝到另一个目录中。
27.nohup(启动命令) 重定向的问题
nohup命令输出到指定文件:
nohup ./start.sh & 默认输出到nohup.out文件( &是让它后台来运行)
nohup ./start.sh >output 2>&1 & 指定输出到output文件 nohup重定向输出日志