GeeksforGeeks(https://www.geeksforgeeks.org/):GeeksforGeeks是一个技术学习平台,它提供了广泛的操作系统知识,包括操作系统概念、进程管理、内存管理、文件系统等内容。
IBM Developer(https://developer.ibm.com/technologies/linux/articles/l-linux-kernel/):IBM Developer提供了广泛的技术文章,其中包括了许多关于Linux内核的文章,涵盖了从基础概念到高级话题的内容。
Linux Journal(https://www.linuxjournal.com/):Linux Journal是一份专门针对Linux用户和开发人员的杂志,提供了广泛的Linux操作系统知识。
Linux.com(https://www.linux.com/):Linux.com是Linux基金会的官方网站,提供了有关Linux操作系统的广泛信息和资源,包括新闻、文章、培训和社区论坛等。
Reddit的r/linux(https://www.reddit.com/r/linux/):Reddit的r/linux是一个专门针对Linux操作系统的社区,其中包含了大量的技术文章、新闻和讨论。
基础部分
这里写目录标题
- 基础部分
- 1、进程和线程的区别?
- 为什么要设计进程?
- 2、进程间通信的机制?
- 3、进程 / 线程 上下文切换的细节?
- 4、进程间的状态转换?
- 5、线程同步的机制?线程的同步和互斥?
- 6、共享内存的原理?
- 7、linux查看磁盘空间的指令?
- 8、linux查看文件信息的命令?
- 9、GDB查看栈帧、寄存器的指令是什么?
- 10、GCC常用编译器选项有哪些?作用分别是什么?
- 11、什么是IO多路复用?select、poll、epoll三种模型的区别?
- 12、LT和ET的区别?
- 13、什么是内存泄漏?采用什么方法来避免或减少这类错误?
- 14、线程池的好处?
- 15、什么是死锁?产生的必要条件?如何避免死锁?
- 16、什么是僵尸进程?孤儿进程?Linux僵尸进程产生原因及解决方法?
- 17、什么是守护进程?如何创建?
- 18、进程调度算法?
- 19、函数调用和系统调用的区别?
- 20、用户态和内核态?
- 21、虚拟内存的实现原理?
- 22、边缘触发和水平触发的区别?
- 23、内存映射的工作机制?内存映射和共享内存的区别?
- 24、线程能否做到共享同一片内存?进程呢?
- 25、`http 4**`状态码
- 26、Linux内核的组成部分?
- 27、中断和异常的区别?
- 28、软链接与硬链接?
- 删除了软链接的源文件,软链接可用吗?
- 29、32bit与64bit有什么区别?
- 30、多进程,哪个函数创建子进程,子进程能访问父进程变量吗?
- 31、Linux的内存回收机制?用了什么数据结构?
- 32、Linux日志系统?
- 33、Vim指令
- 34、find命令如何使用?
- 35、Linux远程传输命令?
- 36、如何在目录下找出大小超过10KB的文件
- 37、常见的Linux压缩包有哪些?
- 38、什么是LVM,它的作用是什么?
- 39、什么是umask?
- 40、Linux是如何连接到Unix的?
- 41、什么是PWD?
- 42、主目录和工作目录之间的区别?
- 43、如何查看二进制文件的内容?
- 44、查看http的并发请求数及其TCP连接状态
- 45、Linux开机启动顺序?
- 46、页和段的区别?
- 47、
- 48、
- 49、
- 50、
- 51、
- 52、
- 53、
- 54、
- 55、
- 56、
- 57、
- 58、
1、进程和线程的区别?
进程(Process)和线程(Thread)都是操作系统中执行程序的基本单位,但它们之间有以下区别:
资源占用:进程是系统分配资源的基本单位,一个进程可以拥有多个线程。每个进程都拥有独立的内存空间、文件句柄、设备、CPU 时间等系统资源,而线程共享所属进程的资源。
调度:操作系统会为每个进程分配一定的时间片,通过调度算法来安排进程之间的执行顺序。而线程是由进程创建和调度的,同一个进程内的线程之间可以共享 CPU 时间,并且线程切换的成本比进程切换低。
执行方式:进程之间的通信需要借助进程间通信(IPC)机制,如管道、消息队列、共享内存等。线程之间共享所属进程的内存空间,可以直接读写共享变量,因此线程间的通信更加高效。
安全性:由于线程共享同一进程的内存空间,因此多个线程之间可能会发生竞态条件、死锁等问题,需要使用同步机制来避免这些问题的出现。而进程之间的内存空间是相互独立的,可以避免这些问题的发生。
总之,进程和线程都是操作系统中非常重要的概念,它们各有优缺点,在不同的应用场景下使用。例如,多线程适合处理计算密集型任务,多进程适合处理 I/O 密集型任务。
为什么要设计进程?
进程是操作系统中最基本的概念之一,它是程序运行时分配和管理系统资源的实体。设计进程的主要目的是实现对计算机系统中的资源进行合理分配和管理,使得多个程序可以同时运行,同时又不会出现相互干扰或竞争资源的情况。
主要作用:
实现并发:通过进程,多个程序可以同时在计算机系统中运行,从而实现并发执行,提高计算机的利用率。
实现资源管理:进程可以分配和管理系统资源,包括CPU、内存、I/O设备等,确保不同进程之间的资源不会相互干扰或竞争。
实现进程间通信:进程可以通过进程间通信机制来进行数据共享和协作,实现更加复杂的任务和应用。
2、进程间通信的机制?
在操作系统中,进程间通信(IPC,Inter-Process Communication)是不同进程之间交换信息的一种机制。常用的进程间通信机制包括:
管道(Pipe):管道是一种半双工的通信机制,可以在父子进程之间或兄弟进程之间进行通信。管道可以通过系统调用pipe()创建,读写数据时使用read()和write()系统调用。
命名管道(Named Pipe):命名管道也是一种半双工的通信机制,不同于管道的是,命名管道可以在不相关的进程之间进行通信。命名管道可以通过mkfifo()系统调用创建,读写数据时同样使用read()和write()系统调用。
消息队列(Message Queue):消息队列是一种异步通信机制,可以在不相关的进程之间进行通信。消息队列可以通过msgget()系统调用创建,读写数据时使用msgsnd()和msgrcv()系统调用。
共享内存(Shared Memory):共享内存是一种高效的通信机制,可以使得不相关的进程之间共享同一个内存区域。共享内存可以通过shmget()系统调用创建,读写数据时使用shmat()和shmdt()系统调用。
信号量(Semaphore):信号量是一种同步通信机制,可以用来实现多个进程之间的互斥和同步。信号量可以通过semget()系统调用创建,读写数据时使用semop()系统调用。
套接字(Socket):套接字是一种通用的通信机制,可以在不同主机之间进行网络通信,也可以在同一主机上的不相关进程之间进行通信。套接字可以通过socket()系统调用创建,读写数据时使用send()和recv()系统调用。
3、进程 / 线程 上下文切换的细节?
上下文切换是指操作系统将当前进程或线程的执行状态(如寄存器内容、程序计数器、堆栈指针等)保存在内存中,然后加载下一个进程或线程的执行状态,以实现进程或线程的切换。下面是进程和线程上下文切换的一些细节:
进程上下文切换:当操作系统决定将 CPU 时间片分配给另一个进程时,它会执行以下步骤:
保存当前进程的执行状态,包括 CPU 寄存器、程序计数器、进程状态等;
将新的进程的执行状态从内存中读入 CPU 寄存器、程序计数器等寄存器中;
更新进程的状态为“运行中”(Running),开始执行新的进程。
进程上下文切换需要保存和恢复较多的信息,包括进程的内存映像、文件描述符等,因此它的开销比线程上下文切换更大。
线程上下文切换:当操作系统将 CPU 时间片分配给同一进程中的另一个线程时,它会执行以下步骤:
保存当前线程的执行状态,包括 CPU 寄存器、程序计数器、线程状态等;
将新的线程的执行状态从内存中读入 CPU 寄存器、程序计数器等寄存器中;
更新线程的状态为“运行中”(Running),开始执行新的线程。
线程上下文切换只需要保存和恢复较少的信息,因为同一进程中的线程共享相同的地址空间、文件描述符等资源。
上下文切换的开销:由于上下文切换需要保存和恢复进程或线程的执行状态,因此它会带来一定的开销。上下文切换的开销主要来自于 CPU 寄存器的保存和恢复、内存映像的切换等操作。为了尽量减小上下文切换的开销,可以采用以下策略:
减少进程或线程的数量,避免频繁地进行上下文切换;
尽量避免在关键路径上使用锁等同步机制,减少线程间的竞争;
使用多核 CPU 来实现并发,避免在同一核上频繁地进行上下文切换。
4、进程间的状态转换?
进程的状态是描述进程所处情况的属性集合,进程可以在不同的状态之间转换,这些状态包括:
新建(New):进程被创建但还没有被调度执行。
就绪(Ready):进程已经准备好执行,等待分配 CPU 时间片。
运行(Running):进程正在执行,占用 CPU 时间片。
阻塞(Blocked):进程因为等待某种事件(如 I/O 操作)而暂停执行,等待事件发生。
终止(Terminated):进程已经执行完毕或被操作系统终止。
进程的状态转换是由操作系统内核管理的,下面是一些常见的状态转换:
新建 -> 就绪:当进程被创建后,它会被加入到就绪队列中等待调度执行。
就绪 -> 运行:当进程被调度到 CPU 上执行时,它的状态从就绪变为运行。
运行 -> 就绪:当进程的时间片用完或被中断时,它的状态从运行变为就绪,等待下一次调度执行。
运行 -> 阻塞:当进程需要等待某种事件(如 I/O 操作)时,它的状态会从运行变为阻塞。
阻塞 -> 就绪:当进程等待的事件发生时,它的状态会从阻塞变为就绪,等待调度执行。
运行 -> 终止:当进程执行完毕或被操作系统终止时,它的状态会变为终止。
需要注意的是,进程状态转换是一种复杂的过程,涉及到进程调度、中断处理、I/O 操作等多方面的因素,操作系统需要根据具体的情况来判断何时进行状态转换,以保证系统的正确性和性能。
5、线程同步的机制?线程的同步和互斥?
线程同步指的是在多个线程访问共享资源时,确保它们的访问顺序和结果的正确性的一种机制。线程同步通常涉及到线程的互斥和同步操作。
线程的互斥指的是在多个线程访问共享资源时,只允许一个线程访问,其它线程需要等待当前线程释放资源之后才能访问。线程的互斥操作可以通过锁来实现,锁是一种同步机制,它允许线程对共享资源进行互斥访问。
线程的同步指的是在多个线程之间进行协调,保证它们按照某种顺序执行,以确保程序的正确性。线程的同步操作可以通过信号量、事件等机制来实现。
常见的线程同步机制包括:
互斥锁(Mutex):用于控制多个线程对共享资源的访问顺序,只允许一个线程访问共享资源。
读写锁(ReadWrite Lock):允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。
条件变量(Condition Variable):用于线程之间的协调,允许线程在某个条件下等待或唤醒其他线程。
信号量(Semaphore):用于限制同时访问共享资源的线程数目。
屏障(Barrier):用于同步多个线程的执行,等待所有线程都达到某个点之后再继续执行。
线程同步和互斥是保证多线程程序正确性的重要手段,它们可以避免由于多个线程同时访问共享资源而导致的数据不一致、死锁等问题。
6、共享内存的原理?
共享内存是一种进程间通信机制,它的原理是让多个进程共享同一块物理内存区域,从而实现进程之间的数据共享。
共享内存的实现原理通常分为以下几个步骤:
创建共享内存区域:在内核中创建一块共享内存区域,并给这块区域分配一个唯一的标识符。
连接共享内存区域:所有需要访问共享内存区域的进程,需要调用共享内存连接函数,将这块共享内存区域映射到各自的地址空间中。
使用共享内存区域:进程在共享内存区域中读写数据时,可以像操作普通内存一样进行操作,不需要进行任何额外的数据拷贝操作。
分离共享内存区域:当进程不再需要访问共享内存区域时,需要调用共享内存分离函数,将共享内存区域从进程的地址空间中删除。
删除共享内存区域:当所有进程都不再需要访问共享内存区域时,需要调用共享内存删除函数,将这块共享内存区域从内核中删除。
7、linux查看磁盘空间的指令?
Linux 查看磁盘空间的指令是 df。df 可以显示磁盘分区或者挂载点的空间使用情况。
常用的选项包括:
-h:以人类可读的格式显示磁盘空间使用情况,例如 GB、MB 等单位。
-T:显示文件系统的类型。
-i:显示 inode 的使用情况。
$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 1.9G 0 1.9G 0% /dev
tmpfs 388M 1.5M 387M 1% /run
/dev/sda1 20G 7.3G 12G 39% /
tmpfs 1.9G 44M 1.9G 3% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/loop1 56M 56M 0 100% /snap/core18/2128
/dev/loop2 71M 71M 0 100% /snap/lxd/22960
/dev/loop3 67M 67M 0 100% /snap/lxd/22997
tmpfs 388M 16K 388M 1% /run/user/1000
8、linux查看文件信息的命令?
Linux 查看文件信息的命令是 ls,它可以列出指定目录下的文件和子目录。
常用的选项包括:
-l:以长格式显示文件信息,包括权限、所有者、大小、修改日期等信息。
-a:显示所有文件,包括以点号(.)开头的隐藏文件。
-h:以人类可读的格式显示文件大小,例如 GB、MB 等单位。
-i:显示 inode 号。
9、GDB查看栈帧、寄存器的指令是什么?
在 GDB 中查看栈帧、寄存器等调试信息,可以使用以下命令:
info frame 或 i f: 查看当前栈帧的信息,包括当前函数名、参数值、局部变量等。
info registers 或 i r: 查看当前 CPU 寄存器的值。
x /nfu addr: 查看内存地址 addr 开始的 n 个单位(默认为字节),并使用格式 f 进行显示。常用的格式包括:
x /1x addr:按十六进制格式显示一个字节。
x /2x addr:按十六进制格式显示两个字节。
x /4x addr:按十六进制格式显示四个字节。
x /8x addr:按十六进制格式显示八个字节。
x /nfu $reg: 查看寄存器 $reg 中的值,并使用格式 f 进行显示。
例如,x /wx $eax 表示按十六进制格式显示 eax 寄存器中的值,每个单位占用四个字节。
info all-registers:查看所有 CPU 寄存器的值。
10、GCC常用编译器选项有哪些?作用分别是什么?
GCC 是一款强大的编译器,支持多种编程语言,包括 C、C++、Objective-C、Fortran、Ada 等。以下是 GCC 常用的编译器选项及其作用:
-c:只编译源文件,生成目标文件,不进行链接。通常用于编译多个源文件,生成多个目标文件,然后链接成一个可执行文件。
-o:指定生成的可执行文件或目标文件的名称。例如,gcc -o hello hello.c 表示将 hello.c 编译成可执行文件 hello。
-Wall:开启所有警告信息,包括一些常见的代码问题,例如未使用的变量、类型不匹配、不安全的类型转换等。
-Werror:将警告信息视为错误,编译过程中遇到警告信息时将停止编译。这可以帮助程序员尽早发现代码问题,并迫使他们进行修复。
-g:生成调试信息,将编译后的目标文件与源代码进行关联,以便在调试时能够定位到源代码的位置。
-O:指定代码优化等级。可选的优化等级包括 -O0(不优化)、-O1(简单优化)、-O2(常规优化)、-O3(高级优化)等。通常情况下,使用 -O2 或 -O3 可以提高代码的运行效率。
-I:指定头文件的搜索路径。例如,gcc -I /usr/local/include hello.c 表示将 /usr/local/include 目录加入头文件搜索路径。
-L:指定库文件的搜索路径。例如,gcc -L /usr/local/lib -lmylib hello.c 表示将 /usr/local/lib 目录加入库文件搜索路径,并链接名为 libmylib 的库文件。
-l:链接指定的库文件。例如,gcc -L /usr/local/lib -lmylib hello.c 表示链接名为 libmylib 的库文件。
11、什么是IO多路复用?select、poll、epoll三种模型的区别?
IO多路复用是一种高效的I/O模型,它允许一个进程同时监听多个文件描述符的可读可写状态,从而实现并发I/O操作。在传统的I/O模型中,当一个文件描述符进行I/O操作时,程序会被阻塞,直到该操作完成。而在IO多路复用模型中,程序可以在一个循环中监听多个文件描述符的事件,并根据事件类型进行相应的操作,从而避免了阻塞等待的情况,提高了I/O操作的效率。
常见的IO多路复用函数有select、poll、epoll等。select函数可以同时监听多个文件描述符的可读可写状态,但由于其实现采用了线性扫描的方式,导致在高并发场景下效率较低。poll函数采用了链表的方式存储文件描述符,相对于select来说性能更优,但仍存在效率问题。而epoll函数则采用了红黑树的数据结构,可以高效地管理大量文件描述符,因此在高并发场景下性能更好。
select、poll、epoll 都是 Linux 中常用的多路复用 I/O 模型,用于实现高效的 I/O 处理。它们的区别如下:
select 和 poll 采用轮询的方式来检查每个文件描述符是否就绪,而 epoll 利用回调机制,当文件描述符就绪时自动调用相应的回调函数,因此效率更高。
select 和 poll 模型的文件描述符上限受到系统限制,一般为 1024,而 epoll 没有这个限制,可以支持数万个并发连接。
select 和 poll 采用同步 I/O 机制,而 epoll 支持同步和异步两种 I/O 机制。
select 和 poll 需要在每次调用时传递所有监视的文件描述符,而 epoll 可以在注册时设置事件触发方式,并且支持动态添加和删除文件描述符,因此更加灵活。
总的来说,select 和 poll 是较为简单的 I/O 模型,适用于连接数较少的情况,而 epoll 则是效率更高、更加灵活的 I/O 模型,适用于连接数较多的高并发场景。
12、LT和ET的区别?
LT(Level-Triggered)和 ET(Edge-Triggered)是 epoll 中用来设置事件触发方式的两种模式。
在 LT 模式下,当 epoll_wait() 检测到文件描述符就绪时,会将该事件加入就绪队列中,然后等待下一次 epoll_wait() 调用,即每次只要文件描述符处于可读/可写状态,就会触发 epoll_wait()。
而在 ET 模式下,当文件描述符状态发生变化时才会触发 epoll_wait(),即只有在文件描述符状态发生变化的瞬间才会触发一次事件,之后 epoll_wait() 将会阻塞等待下一次事件的发生。换言之,ET 模式只有在文件描述符状态从未就绪变为就绪时才会触发一次事件,而在就绪状态中持续触发事件。
因此,ET 模式需要对文件描述符进行非阻塞读写操作,以避免 epoll_wait() 的阻塞。另外,在 ET 模式下,需要将文件描述符设置为非阻塞模式,并要求一次性将所有数据读取完毕,否则可能会导致事件无法触发。
总之,LT 模式是默认模式,适用于大多数情况;ET 模式需要更为精细的处理,可以提高性能,但需要特别注意数据读取的方式。
13、什么是内存泄漏?采用什么方法来避免或减少这类错误?
1.用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元即为内存泄露。
2.使用的时候要记得指针的长度,malloc的时候得确定在那里free,对指针赋值的时候应该注意被赋值指针需要不需要释放,动态分配内存的指针最好不要再次赋值。
14、线程池的好处?
线程池是一种常见的多线程编程技术,它维护了一组预先创建好的线程,当有任务需要处理时,线程池将空闲线程分配给任务,处理完任务后,线程又会回到线程池中等待下一次任务的到来。线程池的好处包括:
提高程序性能:线程池可以有效地利用 CPU 和内存资源,避免了线程的频繁创建和销毁,提高了程序的执行效率。
简化编程:使用线程池可以简化多线程编程的复杂性,避免了手动管理线程的繁琐工作,提高了编程效率。
提高系统稳定性:线程池可以限制线程的数量,避免了过多线程造成的资源浪费和系统崩溃风险。
提高代码可维护性:线程池将线程的创建和销毁等细节封装在一起,使得代码更加清晰和可维护。
支持任务队列:线程池通常与任务队列结合使用,可以有效地控制任务的处理顺序和速率,避免了任务的重复执行和阻塞等问题。
15、什么是死锁?产生的必要条件?如何避免死锁?
死锁(Deadlock)指的是两个或多个进程在执行过程中,因竞争资源而产生的一种互相等待的现象,导致程序无法继续执行下去。
死锁的产生必须满足以下四个必要条件:
互斥条件:资源不能被共享,一次只能被一个进程使用。
请求和保持条件:已经获得了某些资源的进程可以请求新的资源,同时不释放已占有的资源。
不剥夺条件:资源不能被强行抢占,只能由持有它的进程释放。
循环等待条件:进程之间形成一种头尾相连的循环等待资源的关系。
避免死锁的方法主要有以下几种:
破坏互斥条件:将互斥的共享资源改为可以多个进程同时访问。
破坏请求和保持条件:先申请所有的资源,再执行。
破坏不剥夺条件:当一个进程请求新的资源而得不到满足时,它必须释放已经占有的资源。
破坏循环等待条件:将系统中的所有资源进行编号,按照编号顺序请求资源,释放则反序。
除了死锁预防之外,还可以采用死锁检测和死锁恢复来处理死锁问题。死锁检测是指通过算法判断系统是否存在死锁,若存在则采取措施消除;而死锁恢复是指采取某种方法将进程从死锁状态中恢复过来,如抢占资源、回滚进程等。
16、什么是僵尸进程?孤儿进程?Linux僵尸进程产生原因及解决方法?
在Linux操作系统中,进程在终止时需要被内核回收资源,如果进程的父进程没有及时调用wait/waitpid函数等待子进程的退出信息,就会导致子进程成为僵尸进程(Zombie Process)。僵尸进程的状态是已经退出,但是其在进程表中的结构体还没有被完全清除,此时它的进程ID(PID)和进程名称等信息都能被查询到,但已经不能执行任何操作。
另外,当父进程已经退出,而它的子进程还在运行,就会产生孤儿进程(Orphan Process)。孤儿进程会被init进程(PID为1的进程)领养,并由init进程负责对其进行善后处理。
造成僵尸进程的原因是父进程没有及时回收子进程的资源。解决方法一般有以下几种:
父进程调用wait/waitpid函数来回收子进程的资源。
父进程捕获SIGCHLD信号,然后在信号处理函数中回收子进程资源。
在创建子进程时,使用信号机制屏蔽SIGCHLD信号,然后在合适的时候解除信号屏蔽。
父进程忽略SIGCHLD信号,由内核自动回收僵尸进程。这种方法不建议使用,因为产生大量僵尸进程会影响系统性能。
对于孤儿进程,由于其父进程已经不存在,因此需要确保子进程不会一直运行下去,可以让其成为init进程的子进程,由init进程负责回收资源。
17、什么是守护进程?如何创建?
守护进程(Daemon Process)是一种在后台运行的特殊进程,它独立于控制终端,不受控制终端影响,可以在系统启动时自动启动,并在系统关闭时自动退出。守护进程通常用于提供某种系统服务或运行某种长期运行的应用程序。
守护进程的创建步骤一般如下:
创建一个新进程,并在子进程中调用setsid函数,创建一个新的会话,并使该进程成为该会话的组长进程和新会话的首进程,与控制终端脱离关系。
关闭标准输入、标准输出和标准错误输出文件描述符,防止守护进程向这些文件描述符输出信息,因为此时守护进程无法与控制终端进行交互,如果向这些文件描述符输出信息会导致系统出现不可预知的错误。
在守护进程中执行业务逻辑。
处理信号,守护进程一般会处理SIGHUP、SIGTERM、SIGINT等信号,例如在收到SIGHUP信号时,守护进程可以重新读取配置文件等操作。
18、进程调度算法?
进程调度算法是操作系统中的一个重要概念,用于决定在多道程序环境下,哪些进程能够在 CPU 上执行,以及如何为这些进程分配 CPU 时间。操作系统中的进程调度算法主要有以下几种:
先来先服务调度算法(FCFS):按照进程到达的先后顺序进行调度,非抢占式调度。
短作业优先调度算法(SJF):按照进程执行的时间长度进行排序,将执行时间短的进程先调度,非抢占式调度。
优先级调度算法(Priority Scheduling):按照进程的优先级进行调度,优先级高的进程先调度,可为抢占式或非抢占式调度。
时间片轮转调度算法(Round Robin):每个进程被分配一个时间片,当时间片用完时,进程被挂起,然后放到就绪队列末尾,等待下一次调度,非抢占式调度。
多级反馈队列调度算法(Multilevel Feedback Queue):把就绪队列分为多个队列,每个队列有不同的优先级,时间片也不同,一个进程在一个队列中完成时间片后,如果仍未完成,就会被移到更高级别的队列中,可为抢占式或非抢占式调度。
最高响应比优先调度算法(Highest Response Ratio Next):通过计算每个进程的响应比来选择下一个要运行的进程,响应比越高的进程越先运行。
19、函数调用和系统调用的区别?
函数调用和系统调用是两个不同的概念。主要区别在于它们的实现方式和所处的上下文环境,函数调用是程序内部的过程,系统调用是程序与操作系统之间的过程。
函数调用是指程序调用自身或其他函数的过程,是一种程序内部的调用方式,通常使用栈实现。函数调用是在同一进程中完成的,调用过程是通过将参数压入栈中、跳转到函数入口并执行函数体、最后将结果返回给调用者来实现的。
系统调用是指程序向操作系统请求某项服务的过程,例如读写文件、创建进程、发送消息等操作。系统调用是在进程和操作系统之间进行的,需要通过 CPU 特权级别的切换来完成,通常使用中断实现。系统调用请求涉及到用户态和内核态的切换,需要进行内核态的安全检查和处理,效率相对较低。
20、用户态和内核态?
用户态和内核态是指操作系统中不同的运行级别。
在用户态中,程序运行在受限的、隔离的、安全的环境中,只能访问自己的地址空间,不能直接访问操作系统内核的资源和硬件设备。程序执行在用户态时,可以执行的操作和可访问的资源受到限制,例如不能直接访问 I/O 设备、内存管理单元和中断控制器等硬件资源,这些操作需要通过系统调用向内核发起请求。
而在内核态中,操作系统拥有更高的权限和更广泛的控制能力,可以访问硬件设备、系统资源和其他进程的地址空间,执行更加底层的操作。当程序需要进行一些特权级别的操作时,如访问硬件设备或修改内存映射等,需要进入内核态。程序进入内核态需要通过系统调用或异常等方式,将程序的执行权限转移到操作系统内核中,完成需要特权级别的操作后再返回用户态。
21、虚拟内存的实现原理?
虚拟内存是一种计算机内存管理技术,它允许程序使用比实际可用物理内存更大的地址空间,从而使得程序运行更加灵活。其主要实现原理包括分页和页面置换。
分页是将进程的虚拟地址空间划分成大小相等的虚拟页,每个虚拟页映射到物理内存中的一个物理页。操作系统将虚拟地址空间和物理内存进行映射,每个进程拥有自己的页表,用于将虚拟页映射到物理页。当程序访问一个虚拟页时,操作系统会根据页表中的映射关系,将虚拟页的内容读取到物理内存中。
页面置换是将物理内存中不常用的页面换出到硬盘的过程,以便为其他页面腾出空间。当物理内存不足时,操作系统需要选择一些物理页面进行置换,以便为新的虚拟页面腾出空间。页面置换算法根据不同的策略选择要被置换的页面,例如最近最少使用算法(LRU)或先进先出算法(FIFO)等。
在实际的实现中,操作系统使用页表来记录虚拟页和物理页之间的映射关系,使用硬件支持的地址转换机制实现虚拟地址到物理地址的转换。为了提高访问效率,操作系统还采用了预读取、页面共享和页面缓存等技术。
虚拟内存的实现原理可以有效地解决内存管理中的空间限制和保护问题,提高了系统的稳定性和可靠性。但是,虚拟内存也会带来一定的开销和复杂性,例如页表的维护和页面置换的开销,需要权衡设计和实现。
22、边缘触发和水平触发的区别?
边缘触发和水平触发是事件驱动 IO 中常用的两种触发方式,它们的主要区别在于事件通知的时机不同。
在水平触发中,如果一个文件描述符上发生了事件,只要这个事件没有被处理,内核就会一直通知应用程序这个文件描述符上的事件。这意味着应用程序需要在每个事件循环中处理所有待处理的事件,否则就会阻塞在那里,等待下一个事件到来。换句话说,水平触发模式下,只有文件描述符上的状态发生改变时,才会通知应用程序。
而在边缘触发中,只有在文件描述符上的状态发生变化时,才会通知应用程序一次,这一次事件只会通知应用程序当前的状态,并不会重复通知。这意味着应用程序需要立即处理这个事件,并在下一个事件循环中等待下一个事件到来。如果应用程序没有及时处理这个事件,那么这个事件将被丢弃,因为下一次事件通知并不会重复告知这个事件。
边缘触发可以更好地利用系统资源,因为它只会在必要的时候通知应用程序,并且只会通知一次。但是,使用边缘触发需要应用程序具备更高的实时响应能力,以确保在事件到达时立即进行处理。水平触发则相对更简单一些,但需要应用程序在事件循环中显式处理所有待处理的事件。
23、内存映射的工作机制?内存映射和共享内存的区别?
内存映射是将一个文件或者其他对象映射到进程的地址空间,从而使得应用程序能够像访问内存一样访问这个对象,而不需要进行繁琐的文件I/O操作。在内存映射的过程中,内核会将映射的文件的某一段区域映射到进程的地址空间,当应用程序访问该区域时,内核会将访问请求映射为对文件的读写操作。这样,应用程序就能够像访问内存一样快速地对文件进行读写,而不需要进行系统调用和数据拷贝等操作。
内存映射和共享内存都是将一个对象映射到进程的地址空间,但是它们的实现方式和使用场景略有不同。内存映射一般用于将文件或其他对象映射到进程的地址空间中,而共享内存主要用于在进程间共享数据。此外,共享内存需要使用特殊的系统调用来创建和管理共享内存段,而内存映射则可以使用通用的文件I/O操作和mmap()系统调用进行实现。
需要注意的是,内存映射和共享内存都需要对内存空间的访问进行同步和管理,以避免并发访问带来的竞态条件和一致性问题。在使用内存映射和共享内存时,需要采用适当的同步机制(如信号量、互斥量等)来保证数据的一致性和正确性。
24、线程能否做到共享同一片内存?进程呢?
线程可以共享同一片内存,因为在同一个进程中的所有线程都共享该进程的虚拟地址空间,因此它们可以互相访问同一片内存区域。这种内存共享的方式可以用于线程之间的通信和数据共享,例如通过共享内存来实现线程之间的消息传递或者共享某些数据结构。
进程也可以共享同一片内存,但是需要使用特定的机制,例如共享内存(Shared Memory)等,因为不同进程拥有自己独立的地址空间,它们之间不能直接访问彼此的内存。共享内存是一种特殊的内存区域,它可以被多个进程共享,这样不同进程之间就可以通过访问同一片共享内存来进行通信和数据共享。共享内存的实现方式包括 System V 共享内存和 POSIX 共享内存等。
25、http 4**
状态码
400
服务器无法理解请求的格式401
当前请求需要用户验证403
服务器理解请求客户端的请求,但是拒绝执行此请求404
找不到如何与URL相匹配的资源
26、Linux内核的组成部分?
Linux内核的组成部分主要包括以下几个方面:
进程管理模块:包括进程调度、进程创建、进程撤销、进程通信等功能,通过对进程的管理,实现了多进程并发执行。
内存管理模块:主要负责虚拟内存管理、内存映射、页面置换等功能,通过对内存的管理,实现了高效的内存使用和管理。
文件系统模块:负责文件系统的管理和实现,包括对文件的读写、创建和删除等操作,通过对文件系统的管理,实现了文件的可持久化存储和共享。
网络协议栈:包括网络协议的处理和管理,如 TCP/IP、UDP、ICMP 等协议,通过网络协议栈的实现,实现了网络通信和数据传输。
设备驱动程序:包括各种设备驱动程序,如键盘、鼠标、磁盘等设备的驱动程序,通过对设备的管理,实现了对硬件设备的控制和使用。
此外,Linux内核还包括各种系统调用、中断处理、系统管理等模块,这些模块共同构成了一个完整的操作系统内核,为用户提供了稳定、高效的操作系统环境。
27、中断和异常的区别?
中断和异常都是处理器与操作系统交互的机制,它们的区别如下:
中断是由硬件设备发起的,是一种异步事件,例如,输入输出设备的数据传输完成、时钟到期等等。异常是由程序运行期间出现的错误或特殊条件引起的,是一种同步事件,例如,除数为零、地址无效等等。
中断和异常的响应时间不同。中断需要先保存当前进程的状态,然后转向中断服务程序处理中断请求,处理完成后再返回到原进程继续执行,因此响应时间相对较长;而异常是在当前进程执行过程中发生的,处理异常时可以直接处理或中止当前进程,响应时间相对较短。
中断和异常处理的方式也不同。中断需要在操作系统内核中注册中断处理程序,在中断请求到达时执行相应的中断处理程序;而异常则是通过操作系统的异常处理程序进行处理。
中断和异常的处理优先级也不同。中断的优先级通常高于异常,因为中断需要快速响应外设的请求,而异常则是程序错误或异常情况的处理。
28、软链接与硬链接?
软链接和硬链接都是用于在文件系统中创建一个指向另一个文件的链接,但它们的实现方式和用途略有不同。
软链接(symbolic link)是一个指向目标文件的指针,它是一个独立的文件,保存着目标文件的路径信息。当访问软链接时,系统会自动将访问请求转发到链接指向的目标文件上。软链接可以跨越不同的文件系统,也可以指向不存在的文件或目录,因此它更为灵活。
硬链接(hard link)是在文件系统中创建一个文件名,它与原文件名指向同一份数据,也就是说,它们共享同一个 inode。因为硬链接与原文件名共享 inode,所以它们的权限、属性、时间戳等信息都是相同的。硬链接只能在同一文件系统内创建,且只能指向已经存在的文件,因此它的使用场景相对较为有限。
删除了软链接的源文件,软链接可用吗?
删除了软链接的源文件后,软链接仍然存在,但是软链接不再指向任何文件,因此无法使用。如果试图通过软链接访问已删除的源文件,则会收到“文件不存在”的错误消息。
29、32bit与64bit有什么区别?
32位和64位是计算机中用于描述处理器、操作系统和应用程序所能处理的数据位数的概念。
在32位系统中,处理器和操作系统每次只能处理32位数据,所以最大可寻址空间为2的32次方(约为4GB),应用程序也只能使用这个范围内的内存。而在64位系统中,处理器和操作系统每次可以处理64位数据,所以最大可寻址空间为2的64次方,远远大于32位系统,这样应用程序也可以使用更大的内存。
由于处理器和操作系统的数据位数的不同,导致32位系统和64位系统之间存在以下几个方面的差别:
内存寻址能力:64位系统能够处理更大的内存,可以使用更大的物理内存,以及更多的虚拟地址空间。
数据处理能力:64位系统处理器可以同时处理更多的数据,可以提高计算效率和程序的执行速度。
二进制代码兼容性:64位系统不能直接运行32位的二进制代码,需要在操作系统层面提供兼容支持,或者使用虚拟化技术。
应用程序性能:32位应用程序在64位系统上运行时需要进行兼容性处理,可能会导致性能下降。
驱动程序兼容性:64位系统需要专门的64位驱动程序,而一些老的设备可能没有64位驱动程序支持,导致无法在64位系统上使用。
30、多进程,哪个函数创建子进程,子进程能访问父进程变量吗?
在Unix/Linux操作系统中,可以使用fork()函数创建子进程。该函数会在当前进程中复制一个新的进程,使得父进程和子进程拥有相同的代码段、数据段和堆栈段等资源。fork()函数的返回值为0,表示当前进程是子进程;返回值为正整数,表示当前进程是父进程;返回值为负数,表示fork()函数调用失败。
在子进程中,可以访问父进程的变量,但是需要注意以下几点:
a、子进程会继承父进程的地址空间,因此子进程可以访问与父进程相同的全局变量和静态变量。
b、父进程和子进程各自拥有自己的栈段和堆段,因此它们之间的局部变量和动态分配的内存空间是独立的。
c、子进程对父进程的变量的修改不会影响到父进程中的对应变量,因为子进程是在父进程的地址空间的副本上运行的。
31、Linux的内存回收机制?用了什么数据结构?
Linux的内存回收机制主要包括页面置换(Page Replacement)和内存压缩(Memory Compression)两种机制。
页面置换是指将占用内存的页面(Page)从内存中置换出去,以便为需要更多内存的进程腾出空间。Linux内核通过缺页异常(Page Fault)机制来实现页面置换。当一个进程请求访问一个不在内存中的页面时,CPU会产生一次缺页异常,内核就会根据其页面置换算法来决定哪些页面需要置换出去。常见的页面置换算法包括FIFO、LRU、CLOCK等。
内存压缩是指将进程占用的内存中的一些空间压缩,以腾出更多的内存空间。Linux内核采用的是Zswap和Zram两种内存压缩方式。Zswap是将压缩后的页面存储在一个特殊的压缩池中,Zram则是将页面压缩后存储在一个虚拟的块设备上。当需要使用压缩后的页面时,内核会将其解压缩后再写回到内存中。
Linux内核在页面置换和内存压缩过程中使用了多种数据结构,包括双向链表、红黑树、哈希表等。例如,在页面置换算法中,LRU算法使用了双向链表和哈希表,用于维护页面的使用顺序和快速查找某个页面是否在内存中;CLOCK算法则使用了循环链表和红黑树,用于维护页面的访问情况和快速查找某个页面是否需要置换。在Zswap和Zram中,内核使用了LZO、LZ4等压缩算法来对页面进行压缩。
32、Linux日志系统?
Linux日志系统是用于记录系统事件和状态信息的重要组件。它可以帮助系统管理员监控和调试系统,同时也可以提供有用的信息以便于诊断和解决问题。Linux日志系统主要包括以下几个部分:
内核日志(Kernel log):内核日志是Linux系统的核心部分,它记录了所有与内核相关的事件和错误信息,如系统启动信息、设备驱动程序的加载信息、进程异常终止等。内核日志的记录方式可以通过syslog-ng或rsyslogd等系统日志服务程序进行配置。
系统日志(System log):系统日志是记录系统事件和状态信息的主要组件,它包括了许多常见的日志文件,如/var/log/messages、/var/log/secure、/var/log/maillog等。这些日志文件包含了系统各个方面的信息,包括系统进程、用户登录、应用程序启动和关闭等。系统日志的记录方式同样可以通过syslog-ng或rsyslogd等系统日志服务程序进行配置。
应用程序日志(Application log):应用程序日志是由应用程序生成的信息,它通常记录了应用程序的运行状态、错误信息和调试信息等。这些日志文件通常存储在应用程序的安装目录下,也可以通过配置日志服务程序来集中管理。
Linux日志系统使用了多种数据结构来管理日志数据,其中最常用的是环形缓冲区(Circular Buffer)。环形缓冲区是一种循环队列,它可以在写满后将最早的日志数据覆盖掉,以实现循环记录最新的日志信息。此外,Linux还使用了红黑树等数据结构来管理日志文件和日志级别等信息。
33、Vim指令
Vim是一个文本编辑器,它可以通过键盘上的各种指令来进行文本编辑。以下是一些常用的Vim指令:
i: 进入插入模式,可以开始编辑文本。
Esc: 退出插入模式,返回普通模式。
:w: 保存当前文件。
:q: 退出Vim。
:wq: 保存并退出。
:x: 保存并退出,只有当文件被修改过时才会执行保存。
h, j, k, l: 在普通模式下,这四个键分别对应左、下、上、右,可以移动光标。
dd: 在普通模式下,删除当前行。
dw: 在普通模式下,删除当前光标位置到下一个单词的开头。
yy: 在普通模式下,复制当前行。
p: 在普通模式下,将剪贴板中的内容粘贴到当前光标位置。
u: 在普通模式下,撤销上一次操作。
Ctrl-r: 在普通模式下,恢复上一次撤销的操作。
/pattern: 在普通模式下,搜索文本中包含“pattern”的部分。
:s/old/new/g: 在普通模式下,将当前行中所有出现的“old”替换为“new”。
34、find命令如何使用?
35、Linux远程传输命令?
在 Linux 中,可以使用多种命令进行远程传输文件,以下是其中一些常用的命令:
scp 命令:使用 Secure Copy (scp) 命令可以通过 SSH 协议在远程主机之间安全地传输文件,命令格式如下:
scp [options] [source] [destination]
其中,options 表示选项,source 表示源文件路径,destination 表示目标文件路径。
例如,将本地文件 file.txt 传输到远程主机 remote_host 的 /tmp 目录下,可以执行以下命令:
scp file.txt remote_host:/tmp/
sftp 命令:使用 Secure File Transfer Protocol (sftp) 命令可以在 SSH 协议下进行交互式的文件传输,命令格式如下:
sftp [user@]host[:file]
例如,连接到远程主机 remote_host 并传输文件,可以执行以下命令:
sftp remote_host
在 sftp 命令行下,可以使用以下命令进行文件传输:
put:上传本地文件到远程主机
get:从远程主机下载文件到本地
ls:列出远程目录下的文件列表
cd:切换远程目录
mkdir:在远程主机上创建目录
rm:删除远程主机上的文件
以上是两个常用的远程传输命令,还有其他的工具如 rsync、ftp 等,根据具体的需求选择使用。
36、如何在目录下找出大小超过10KB的文件
使用 find命令
find /path/to/directory -type f -size +10k
其中 /path/to/directory 指的是目标目录的路径,-type f 表示查找文件而不是目录,-size +10k 表示查找大小超过10KB的文件,+ 表示查找大于10KB的文件,可以使用 - 表示查找小于10KB的文件,k 表示单位是KB。
37、常见的Linux压缩包有哪些?
常见的Linux压缩包有 tar、gz、bz2、xz 等。
tar:只是打包,不会压缩,通常与其他的压缩程序一起使用,比如 tar.gz、tar.bz2、tar.xz。
gz:使用 GNU gzip 压缩程序压缩的文件,可以使用 gzip 命令进行压缩和解压缩。
bz2:使用 bzip2 压缩程序压缩的文件,可以使用 bzip2 命令进行压缩和解压缩。
xz:使用 XZ Utils 压缩程序压缩的文件,可以使用 xz 命令进行压缩和解压缩。
其中,tar 可以将多个文件和目录打包成一个文件,gz、bz2、xz 可以对文件进行压缩。
38、什么是LVM,它的作用是什么?
LVM(Logical Volume Manager)是Linux系统下的一个逻辑卷管理器,它可以将物理存储设备抽象成逻辑卷,从而实现灵活的存储管理。
LVM的作用如下:
管理存储空间:LVM可以将多个物理存储设备(如硬盘)的空间整合成一个逻辑卷组,从而实现对存储空间的管理。
动态调整分区:LVM可以动态地添加、删除和调整逻辑卷的大小,而无需重新分区或格式化磁盘,从而减少了停机时间。
快照:LVM支持对逻辑卷进行快照,可以对文件系统进行备份或测试等操作,而无需停止运行的应用程序或关机。
RAID:LVM支持RAID 0、1和5,可以在物理存储设备级别上提供数据冗余和可靠性。
目录如何压缩:使用tar命令可以将目录压缩成tar包,例如将目录/home/user1压缩成tar包user1.tar,命令为:
tar -cvf user1.tar /home/user1
其中,-c表示创建tar包,-v表示显示详细信息,-f表示指定输出文件名。
39、什么是umask?
在 Linux 系统中,umask(用户掩码)是一个用于限制文件权限的设置值,它会影响新创建文件和目录的默认权限。当一个新文件或目录被创建时,系统会按照 umask 值和预设的默认权限来计算文件或目录的最终权限。
umask 值是一个三位八进制数,每一位代表一个权限,分别是读(r)、写(w)和执行(x)权限,每一位的值为 0 表示允许该权限,值为 1 表示禁止该权限。例如,umask 值为 022 表示禁止新创建文件或目录的组和其他用户的写入权限,允许所有用户的读取和执行权限。
umask 值通常在 shell 环境变量中设置,可以使用 umask 命令来查看和修改 umask 值。例如,umask 022 命令可以将 umask 值设置为 022。
40、Linux是如何连接到Unix的?
Linux和Unix都是类Unix系统,它们具有类似的系统架构和接口,因此它们可以使用相同的连接方法。
在Linux中,可以通过使用“ssh”命令连接到Unix系统。SSH是Secure Shell的缩写,是一种安全的网络协议,可通过加密连接来确保数据的安全传输。要使用ssh连接到Unix系统,需要知道目标Unix系统的IP地址或主机名,以及具有正确凭据的用户名和密码。
41、什么是PWD?
在Linux和Unix中,pwd是一个命令,用于显示当前工作目录的完整路径名。pwd是"print working directory"的缩写。当您在终端中使用cd命令更改目录时,您可以使用pwd命令来查看您当前的工作目录是哪个目录。pwd命令不需要任何参数。
42、主目录和工作目录之间的区别?
主目录和工作目录是两个不同的概念。
主目录是每个用户的根目录,它是用户登录时的默认目录。主目录通常在/home目录下,并使用用户名命名。
工作目录是用户当前正在使用的目录。当用户在终端上输入命令时,默认情况下,命令在当前工作目录下执行。可以使用pwd命令查看当前工作目录。
在默认情况下,用户登录时的主目录就是当前工作目录。但是,用户可以使用cd命令更改当前工作目录,而不会影响主目录。
43、如何查看二进制文件的内容?
可以使用Linux上的一些命令来查看二进制文件的内容,其中最常用的命令是hexdump和xxd。以下是两个命令的简要介绍:
hexdump
hexdump命令可以将一个文件或标准输入的内容转换成十六进制或其他格式的表示,并输出到标准输出。可以使用-C选项来以十六进制和ASCII码的形式输出文件的内容,如下所示:
hexdump -C filename
这将以每16字节为一行的形式输出文件内容,并在每行的右侧显示相应的ASCII码值。
xxd
xxd命令也可以将二进制文件转换为十六进制格式,并可以将结果输出到标准输出或另一个文件中。可以使用-b选项将文件内容输出为二进制格式,使用-c选项指定每行输出的字节数,使用-g选项指定每组输出的字节数,如下所示:
xxd -b filename
xxd -c 8 -g 1 filename
这将分别以每8字节为一组的二进制格式输出文件内容,并将结果输出到标准输出。
44、查看http的并发请求数及其TCP连接状态
netstat -an | grep :80 | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
这个命令会列出所有与端口80(HTTP)相关的TCP连接,并计算每种状态的数量。
45、Linux开机启动顺序?
BIOS阶段:计算机启动后首先进入BIOS程序阶段,进行硬件自检和系统设置。
BootLoader阶段:BIOS完成硬件自检后,会从磁盘、光盘或网络中加载引导加载程序,例如GRUB、LILO等,这些程序会载入内核并启动。
内核初始化阶段:内核加载后,会进行初始化并创建第一个用户空间进程Init,加载并挂载根文件系统,启动系统服务等。
用户空间初始化阶段:在内核初始化完成后,用户空间初始化阶段就开始了。Init进程会启动各种服务进程,例如systemd等。
用户登录阶段:用户空间初始化完成后,系统等待用户登录,当用户登录后会启动相应的会话管理器,例如X Window System等。
在Linux系统开机启动过程中,可以通过编辑GRUB的启动项、修改Systemd服务配置文件等方式来改变启动顺序和配置。
46、页和段的区别?
在操作系统中,页(page)和段(segment)是两种常用的内存管理方式。
页是操作系统对物理内存的划分方式之一,将物理内存按照固定大小(通常是4KB)划分为多个页,每个页具有相同的大小。操作系统使用页表来将逻辑地址映射到物理地址,使得程序可以访问到所需的物理内存。页的划分方式是一种均匀的划分方式,适用于管理大量连续的物理内存。
段是另一种内存管理方式,它将程序中的逻辑地址划分为多个逻辑段,每个段可以包含代码、数据等多种类型的信息。不同的逻辑段可以有不同的大小,以适应程序的需求。段的划分方式是一种灵活的划分方式,适用于管理程序的各种资源。
总的来说,页和段是内存管理的两种常见方式,二者之间的区别在于划分方式的不同。页主要适用于大量连续的物理内存的管理,而段适用于灵活管理程序中的各种资源。