嵌入式面试题(linux)

 第一章:进程线程的基本概念
1、什么是进程(Process),线程(Thread),有什么区别?

进程和线程都是操作系统中的基本概念,以下是它们的定义和区别:

进程(Process):
进程是操作系统中分配资源和调度的基本单位。一个程序至少要开启一个进程,进程是由进程控制块(PCB)、程序段、数据段三部分组成。一个进程可以包含多个线程,这些线程共享进程的地址空间和资源,并且通过同步机制来协调对共享资源的访问。

线程(Thread):
线程是进程的基本执行单元,是处理器调度的最小单位。一个进程中的每个线程都有自己的线程控制块(TCB)、指令指针(IP)、栈和寄存器组。线程的调度由操作系统负责,当一个线程完成了一次调度后,它将返回自己的进程空间,从而执行该进程的其他线程。

以下是进程和线程的区别:

地址空间:
进程的地址空间是独立的,而线程的地址空间是进程的一部分。这意味着,进程之间的地址空间是相互独立的,而同一进程内的线程之间可以共享数据和内存。

资源拥有:
进程拥有独立的资源,如内存、文件、I/O等,而同一进程内的线程之间可以共享这些资源。这种共享可以通过同步机制来协调,以确保多个线程对共享资源的访问不会发生冲突。

任务执行:
进程是独立的任务执行单元,而线程是在进程内的任务执行单元。一个进程可以有多个线程,但一个线程只能属于一个进程。

崩溃风险:
当一个进程的某个线程崩溃时,整个进程都会受到影响,因为其他线程也共享了该进程的地址空间和资源。相反,多个进程之间的相互独立性更高,一个进程的崩溃不会影响其他进程。

2、多进程(Multi-Process)、多线程(Multi-Thread)的优缺点?

多进程和多线程在操作系统中都具有其优缺点。以下是一些主要的优缺点:

多进程的优点:

独立性强:每个进程都有自己的地址空间和资源,进程之间相互独立,一个进程的崩溃不会影响其他进程。
资源隔离:由于每个进程都有自己的资源,不同进程之间的资源不会相互干扰,这使得多进程在资源管理方面更加稳定和安全。
多进程的缺点:

资源开销大:每个进程都需要分配独立的资源,包括内存、文件等,这使得系统需要为每个进程分配不同的资源,造成了资源开销较大的问题。
上下文切换:当多个进程同时运行时,处理器需要频繁地进行上下文切换,即保存和恢复进程的状态,这会带来一定的性能开销。
多线程的优点:

资源共享:同一进程内的线程可以共享数据和内存,这使得线程之间的协作更加高效。
效率高:由于线程之间共享地址空间和资源,使得多线程在执行时可以更快地访问共享数据,提高了执行效率。
调度方便:操作系统可以方便地对同一进程内的线程进行调度,使得线程之间的切换更加迅速。
多线程的缺点:

同步问题:由于线程之间共享数据和资源,因此需要引入同步机制来确保线程之间的访问不会发生冲突。然而,同步机制的实现可能会带来额外的开销和复杂性。
调度开销:尽管多线程的调度比多进程更高效,但仍然存在调度开销的问题。当线程数量较多时,调度开销可能会对系统性能产生一定的影响。
性能限制:当多个线程同时运行时,由于共享资源的限制,系统的性能可能会受到限制。例如,当某个线程被阻塞时,其他线程的执行也会受到影响。
综上所述,多进程和多线程在操作系统中都具有其优缺点。在实际应用中,需要根据具体场景和需求来选择合适的进程模型。在需要隔离和独立性要求较高的场景下,可以选择多进程;而在需要共享数据和协作频繁的场景下,可以选择多线程。同时,需要注意多进程和多线程可能带来的上下文切换、同步问题、调度开销等挑战,以及如何进行有效的优化和管理。 

3、多进程、多线程同步(通讯)的方法?

多进程和多线程之间的同步和通信可以通过以下几种方法实现:

管道(Pipe):管道是一种进程间通信的方式,可以在不同进程之间传递数据。可以使用管道函数如pipe()、read()和write()等来实现进程间通信。
共享内存(Shared Memory):共享内存是一种高效的进程间通信方式,它可以让多个进程共享同一块内存区域,从而实现数据共享。可以使用共享内存函数如shmget()、shmat()和shmdt()等来实现进程间通信。
信号量(Semaphore):信号量是一种同步机制,它可以用于控制多个进程之间的访问权限。可以使用信号量函数如semget()、semctl()和semop()等来实现进程间同步。
消息队列(Message Queue):消息队列是一种进程间通信方式,它可以让不同进程之间传递消息,并且具有消息的优先级和缓冲机制。可以使用消息队列函数如msgget()、msgrcv()和msgsnd()等来实现进程间通信。
管道和共享内存的组合:管道和共享内存可以组合使用,例如使用管道将数据写入共享内存中,然后其他进程可以从共享内存中读取数据。
套接字(Socket):套接字是一种更为通用的进程间通信方式,可以在不同主机之间传递数据。可以使用套接字函数如socket()、bind()、listen()和connect()等来实现进程间通信。
需要注意的是,多进程和多线程之间的同步和通信往往比较复杂,需要结合具体的场景来选择合适的同步和通信方式,并注意避免死锁、竞争条件等问题。

4、进程线程的状态转换图。什么时候阻塞,什么时候就绪?

推荐博客地址:进程的状态转换 - LRH呀 - 博客园 (cnblogs.com)

5、父进程、子进程的关系以及区别?

父进程和子进程之间的关系主要体现在子进程是由父进程通过操作系统提供的fork函数创建的。在fork函数调用后,父进程会复制自己的内存空间和文件描述符等信息给子进程,使得子进程获得与父进程相似的运行环境。

以下是父进程和子进程之间的区别:

ID:子进程有一个新的进程ID,而父进程的进程ID不同于子进程的进程ID。
内存空间:子进程拥有独立的内存空间,与父进程的内存空间不完全相同。子进程的内存空间是父进程内存空间的一个副本,当父进程修改了某个内存地址上的数据后,子进程在同样的内存地址上的数据也会发生改变。
文件描述符:子进程继承了父进程的文件描述符,可以访问相同的文件。
状态和优先级:子进程继承了父进程的状态、优先级和信号屏蔽字等信息。
资源:子进程继承了父进程的资源,如打开的文件、信号量等。
父子进程之间是独立的,互相不共享代码段和数据段。
补充说明:Linux 系统创建的第 1 个进程叫 init 进程,它是所有进程的祖宗,此进程pid为1。有时候父子进程之间会出现,父进程运行结束了,在内存中销毁了。 而子进程还没运行结束,此时,linux会把子进程挂在linux中的init进程下。

6、什么是进程上下文、中断上下文?

进程上下文和中断上下文是指在操作系统中执行程序时,处理器所维护的两个不同的执行环境。

进程上下文:是在进程中执行的程序的上下文环境。在进程上下文中,处理器保存了程序运行时的所有状态信息,包括程序计数器、寄存器、堆栈指针、内存映射等。当一个进程被调度器调度时,操作系统会将进程的上下文保存到进程控制块(PCB)中,然后加载到内存中的适当位置,以便处理器可以正确地执行该进程。

中断上下文:是在中断处理程序中执行的上下文环境。当一个中断发生时,处理器会保存当前正在执行的进程的上下文,并跳转到中断处理程序的入口地址。在中断处理程序执行完毕后,处理器会恢复之前保存的进程上下文,并将控制权交回被中断的进程。

进程上下文和中断上下文的主要区别在于其用途和执行环境的差异。进程上下文主要用于保存和恢复进程的状态信息,以实现进程的切换和调度;而中断上下文则主要用于保存和恢复中断处理程序的状态信息,以实现中断的处理和返回。

7、一个进程可以创建多少线程,和什么有关

一个进程可以创建的线程数受到操作系统和计算机硬件的限制。

具体的限制因操作系统和硬件的不同而有所不同。在操作系统方面,一些操作系统可能会限制进程可以创建的最大线程数,例如,在一些嵌入式操作系统中,可能只允许创建几个线程。而在其他操作系统中,可能会允许创建更多的线程。例如Windows Server操作系统限制每个进程可以创建2000个线程。

此外,计算机硬件的性能也会对线程数产生影响。在实际情况中,如果创建过多的线程,可能会导致系统性能下降,因为每个线程都需要占用一定的内存和计算资源。因此,需要根据具体的计算机硬件和应用程序的需求来调整线程数。

总的来说,一个进程可以创建的线程数取决于操作系统和计算机硬件的限制,而具体的限制条件需要根据实际情况来确定。

8、线程通讯(锁):

这些锁都是用于线程同步和互斥的机制,以下是它们的简要介绍:

信号量(Semaphore):
信号量是一种计数信号,可以用于控制多个线程对共享资源的访问。它通常由一个计数器和一个等待队列组成,计数器用于记录可用的资源数量,当计数器为零时,表示没有可用的资源,线程将被阻塞。等待队列中保存了被阻塞的线程,直到有可用的资源为止。

读写锁(Read-Write Lock):
读写锁是一种用于控制对共享资源的读写访问的锁。它允许多个线程同时读取共享资源,但只允许一个线程进行写操作。读写锁的实现通常会根据读写操作的特性进行优化,以最大化并发性能。

条件变量(Condition Variable):
条件变量是一种用于线程之间的通信机制。它可以用于在某个条件满足时,唤醒一个或多个等待的线程。条件变量通常与互斥锁一起使用,用于实现复杂的同步和通知机制。

互斥锁(Mutex):
互斥锁是一种用于保护共享资源的机制。它允许多个线程同时访问共享资源的一部分,但只允许一个线程同时访问共享资源的整个区域。当一个线程需要访问共享资源的互斥锁时,其他线程将被阻塞,直到该线程释放锁为止。

自旋锁(Spinlock):
自旋锁是一种基于忙等待的锁机制。当一个线程尝试获取自旋锁时,如果自旋锁已经被其他线程占用,则该线程会在循环中等待自旋锁被释放。自旋锁的好处是可以避免线程进入阻塞状态,从而减少上下文切换的开销,但缺点是可能会消耗大量的CPU时间。

这些锁都是为了实现线程同步和互斥而设计的机制,但每种锁都有其特点和应用场景,需要根据实际情况选择合适的锁机制。

9、什么叫临界区?

临界区是指一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性,需要在同一时间只能被一个线程执行。临界区用于保护共享资源,以避免多个线程同时访问或修改造成的数据竞争和不确定性。

网络编程
1 、TCP、UDP的区别

TCP(传输控制协议)和UDP(用户数据报协议)是两种常见的网络传输协议,它们有以下区别:

连接:TCP是面向连接的协议,而UDP是无连接的协议。在发送数据前,TCP通过三次握手建立连接,而UDP不需要建立连接。
可靠性:TCP提供可靠的数据传输,保证了数据的可靠性和完整性。TCP通过序号、确认应答和超时重传等机制来实现可靠性。而UDP不提供可靠性保证,数据可能丢失、损坏或重复。
传输速度:UDP比TCP快,因为它不需要建立连接和提供可靠性保障。在一些场景中,如视频、音频等实时应用,UDP更适合。
数据量限制:UDP的数据包大小通常受限于底层网络协议(如以太网),一般不超过1472字节。而TCP的数据包大小则取决于操作系统和底层网络协议。
应用场景:TCP适用于可靠性要求高的应用场景,如网页浏览、电子邮件等。UDP适用于对速度和实时性要求高的应用场景,如在线游戏、视频流等。
头部开销:TCP的首部较大,为20个字节,而UDP的首部较小,为4个字节。
总的来说,TCP提供了可靠的连接和数据传输,但相对较慢;而UDP快,但数据传输不可靠。在选择传输协议时,需要根据具体的应用场景来权衡。

2、TCP、UDP的优缺点

TCP和UDP都有各自的优缺点,以下是它们的比较:

TCP的优点:

可靠:TCP提供了可靠的连接,保证了数据的可靠性和完整性,适用于对数据准确性要求高的场景。
高速:TCP的传输速度相对较快,尤其是在底层网络支持的情况下。
适应性:TCP的协议规范和实现独立于底层网络协议,可以适应不同的网络环境。
多路复用:TCP通过连接机制实现了多路复用,可以同时处理多个数据流,提高了传输效率。
TCP的缺点:

连接管理:TCP需要建立连接和断开连接的过程,这可能会导致一定的开销和延迟。
数据顺序:TCP在传输过程中需要维护数据顺序,如果某个数据包丢失或乱序,需要重新发送,这可能会影响传输速度。
数据量限制:TCP的数据包大小受限于底层网络协议,如以太网的最大传输单元(MTU),超过该限制可能导致数据被分割为多个小包传输。
流量控制:TCP的传输速率受限于底层网络协议的带宽,如果发送速率过快,可能导致数据包丢失或传输受阻。
UDP的优点:

快速:UDP的传输速度相对较快,尤其适用于实时性要求高的场景,如在线游戏、视频流等。
灵活性:UDP的数据包大小灵活,可以根据应用需要调整,同时不需要维护数据顺序。
简单:UDP的协议相对简单,易于实现和维护,适用于一些轻量级的应用场景。
多路复用:UDP的多路复用机制可以提高传输效率,同时处理多个数据流。
UDP的缺点:

不可靠:UDP不提供可靠性保障,数据可能丢失、损坏或重复,适用于一些对数据准确性要求不高的场景。
数据顺序:UDP的数据包顺序需要应用程序自行处理,适用于一些简单的应用场景。
数据量限制:UDP的数据包大小通常受限于底层网络协议(如以太网),一般不超过1472字节。4. 流控制:UDP的发送速率受限于底层网络协议的带宽和接收方的能力,可能导致数据包丢失或传输受阻。
数据错误处理:UDP的数据包在传输过程中可能发生错误,如损坏或重复,应用程序需要自行处理这些问题。
连接管理:UDP没有建立连接和断开连接的过程,因此不需要维护连接状态,这使得它更加轻量级,适用于一些简单的应用场景。
3、TCP UDP适用场景

TCP和UDP都有各自的适用场景。

TCP(传输控制协议)通常用于对准确性要求相对高的场景,比如文件传输、接受邮件和远程登录。TCP在传输数据时需要进行数据的确认、重发、排序等操作,因此相对来说效率没有UDP(用户数据报协议)高。

UDP常用于对实时性要求高的场景,例如在线游戏、流媒体传输。UDP不可靠,因此它不适用于需要保证数据完整性和可靠性的应用场景。但因为UDP不需要进行连接管理、确认和重传等操作,所以它的数据传输速度比TCP快。同时,UDP还支持多播技术,可以将数据包发送到多个目的地。

总的来说,TCP和UDP都有各自的优点和适用场景,选择使用哪一种协议,需要根据具体的需求来决定。

4、TCP为什么是可靠连接

TCP之所以被认为是可靠连接,是因为它采用了以下几种机制来确保数据的可靠传输:

确认和应答机制:TCP通过发送数据后等待接收方的确认,以及在数据传输过程中采用应答机制,确保每个数据包都被正确接收。如果接收方没有确认收到某个数据包,发送方将重新发送该数据包,直到接收方确认收到为止。

序列号:TCP给每个数据包分配一个独特的序列号,接收方可以根据序列号对数据包进行排序,确保数据包的顺序正确。

超时重传:如果发送方在一定时间内没有收到接收方的确认,将重新发送数据包,以确保数据包能够被正确传输。

流量控制:TCP通过流量控制机制,确保发送速度不会超过接收方处理速度,避免数据包丢失或传输错误。

拥塞控制:当网络拥塞时,TCP会减缓发送速度,以避免过度拥塞网络,导致数据包丢失。

这些机制的结合,使得TCP能够在网络环境下实现可靠的连接。

5、OSI典型网络模型,简单说说有哪些

OSI(开放式系统互联)典型网络模型是由七个层次组成的模型,每个层次都有其特定的功能和服务。以下是这七个层次及其简要功能:

物理层:这一层的主要功能是建立物理连接,将比特流从一个地方传输到另一个地方,并进行数模转换和模数转换。

数据链路层:这一层的主要功能是为网络层提供服务,确保数据在物理层上的传输可靠。数据链路层还提供了一些错误检测和校正功能。

网络层:这一层的主要功能是进行逻辑地址寻址,实现不同网络之间的路径选择。

传输层:这一层的主要功能是定义传输数据的协议端口号,并进行流控和差错校验。其中最常用的协议是TCP(传输控制协议)和UDP(用户数据报协议)。

会话层:这一层的主要功能是建立、管理和终止会话。会话层还提供了一些同步和对话控制的功能。

表示层:这一层的主要功能是将数据进行加密、解密、压缩、解压缩等处理,以确保数据的完整性和一致性。

应用层:这一层是OSI模型的最上层,它提供了网络服务与最终用户的一个接口,用户可以操作的一个界面终端。

这些层次协同工作,共同构成了一个完整的、完善的网络模型。

6、三次握手、四次挥手

三次握手和四次挥手是TCP协议中建立连接和关闭连接的过程。

三次握手:

客户端向服务器发送SYN(同步)报文,请求建立连接。此时,客户端的SYN=1,ACK=0。

服务器收到客户端的SYN报文后,向客户端发送SYN+ACK(同步+确认)报文,表示确认收到客户端的请求,并请求建立连接。此时,服务器的SYN=1,ACK=1。

客户端收到服务器的SYN+ACK报文后,向服务器发送ACK(确认)报文,表示确认收到服务器的请求。此时,客户端的ACK=1。

四次挥手:

客户端向服务器发送FIN(结束)报文,请求关闭连接。此时,客户端的FIN=1,ACK=0。

服务器收到客户端的FIN报文后,向客户端发送ACK(确认)报文,表示确认收到客户端的请求关闭连接的请求。此时,服务器的ACK=1。

服务器向客户端发送FIN(结束)报文,请求关闭连接。此时,服务器的FIN=1,ACK=0。

客户端收到服务器的FIN报文后,向服务器发送ACK(确认)报文,表示确认收到服务器的请求关闭连接的请求。此时,客户端的ACK=1。

这样,TCP连接就建立成功了,并且确保了连接的可靠性。

1、Linux内核的组成部分

Linux内核主要由以下几个部分组成:

进程调度(SCHED):负责控制CPU对进程的访问,使多个进程能够在同一时间竞争CPU资源。

内存管理(MM):负责管理系统的内存,包括物理内存和虚拟内存,以及内核对内存的访问控制。

虚拟文件系统(VFS):提供对文件系统的统一抽象接口,使得不同的文件系统能够在更高层次上进行访问和操作。

网络接口(NET):提供对网络协议的支持,包括网络接口驱动程序和网络协议的处理。

进程间通信(IPC):提供进程之间的通信机制,包括信号、管道、共享内存等。

模块管理器(MODULES):负责加载和卸载内核模块,以及与模块相关的管理和维护工作。

系统调用接口(SYSCALLS):提供用户空间与内核空间之间的接口,使得用户程序能够调用内核提供的系统功能。

这些组成部分共同构成了Linux内核,使得Linux操作系统具有了强大的功能和灵活性。

2、用户空间与内核通信方式有哪些?

用户空间与内核空间之间的通信方式有以下几种:

系统调用(System Call):当用户程序需要内核提供服务时,可以通过系统调用接口发起系统调用。系统调用是一种由用户程序主动发起的从用户空间向内核空间发送的请求,通常用于完成一些与硬件或系统相关操作,如文件操作、进程控制、内存管理等。

中断(Interrupt):当硬件或软件事件发生时,可以通过中断接口将控制权转移到内核空间。中断通常用于处理异步事件,如硬件中断、时钟中断、进程中断等。

信号(Signal):信号是一种由内核或进程发送的异步事件,用于通知用户程序某些事件已经发生或需要立即执行某个操作。信号通常用于进程间的通信和同步,如进程终止信号、错误信号等。

管道(Pipe):管道是一种半双工的通信机制,用于实现进程之间的数据传输和共享。管道可以是字节流或消息流,可以用于实现进程之间的父子进程通信或进程与内核模块之间的通信。

共享内存(Shared Memory):共享内存是一种高效的进程间通信方式,通过将同一块物理内存映射到多个进程的虚拟地址空间中,使得多个进程可以同时访问和修改该内存区域中的数据。共享内存可以实现不同进程之间的数据共享和同步。

这些通信方式提供了用户空间和内核空间之间的接口,使得用户程序能够调用内核提供的系统功能,同时也实现了用户空间和内核空间之间的数据传输和通信。

3、系统调用read()/write(),内核具体做了哪些事情

当用户程序调用read()或write()系统调用时,内核会执行以下一系列操作:

验证参数:内核会验证用户程序传递的参数是否合法,包括文件描述符、缓冲区地址、字节数等。如果参数不合法,内核将返回错误码,并终止系统调用。

权限检查:内核会检查用户程序是否有足够的权限执行读取或写入操作。如果权限不足,内核将返回错误码,并终止系统调用。

数据传输:如果参数合法且权限检查通过,内核会根据文件描述符所代表的文件类型和文件偏移量,将数据从文件或设备中读取或写入到用户程序的缓冲区中。

缓冲区管理:内核会管理文件缓冲区,确保读取和写入的数据正确地缓存和刷新。在读取和写入完成后,内核会将缓冲区中的数据传递给用户程序或从用户程序接收数据。

内存管理:在读取和写入数据时,内核会管理内存,确保数据的正确存储和访问。如果需要,内核会分配或释放内存,以适应数据的大小和访问需求。

错误处理:在读取或写入操作完成后,内核会检查是否有错误发生。如果有错误发生,内核会记录错误码,并将错误信息传递给用户程序。

返回结果:如果读取或写入操作成功完成,内核会将结果返回给用户程序,包括读取或写入的字节数等。

总之,当用户程序调用read()或write()系统调用时,内核会执行一系列操作来验证参数、检查权限、传输数据、管理缓冲区和内存,并处理错误,并将结果返回给用户程序。这些操作保证了用户程序与内核之间的安全和正确的数据传输。

4、系统调用与普通函数调用的区别

系统调用和普通函数调用在以下几个方面存在区别:

调用方式:系统调用是通过中断实现的,而普通函数调用是通过函数调用实现的。系统调用会将控制权从用户空间切换到内核空间,而普通函数调用是在用户空间内进行的。

调用层次:系统调用是操作系统提供给应用程序的接口,可以访问硬件和系统资源,而普通函数调用通常是为了实现应用程序内部的逻辑。

调用时长:系统调用的处理速度通常比普通函数调用慢,因为系统调用需要额外的开销,例如中断处理和上下文切换。

调用安全性:系统调用在执行时具有更高的安全性,因为它们会进行参数验证和权限检查,而普通函数调用通常不会进行这些检查。

调用范围:系统调用是全局的,可以跨越不同的进程和用户空间,而普通函数调用是局部的,仅限于当前进程和用户空间。

总之,系统调用和普通函数调用在调用方式、调用层次、调用时长、调用安全性和调用范围等方面存在明显的区别。系统调用是为了实现操作系统提供给应用程序的接口,而普通函数调用则是为了实现应用程序内部的逻辑。

5、内核态,用户态的区别

内核态和用户态是操作系统中的两个不同运行级别,它们之间存在以下区别:

权限不同:内核态拥有更高的权限,可以访问系统的所有资源,而用户态只能访问受限的资源,例如内存、硬件设备等。

访问资源:在内核态下,操作系统可以直接访问系统资源,而不需要通过用户程序的请求,而在用户态下,用户程序需要通过系统调用才能访问系统资源。

运行空间:内核态运行在内核空间,拥有系统的全部内存空间,而用户态运行在用户空间,只拥有有限的内存空间。

任务执行顺序:内核态是抢占式执行,优先级更高,可以中断用户态任务的执行,而用户态是协作式执行,优先级较低。

驱动程序:内核态下运行的是驱动程序,用于管理硬件设备的接入和访问,而用户态下运行的则是应用程序和库函数。

内核态和用户态之间的区别是为了保证系统的安全性和稳定性。通过限制内核态的访问权限和资源,可以防止恶意程序对系统造成损害,同时也提供了更好的灵活性和可扩展性。

6、bootloade、内核、根文件的关系

BootLoader、内核和根文件系统是操作系统启动的三个重要组成部分,它们之间的关系如下:

BootLoader:BootLoader是操作系统启动时首先执行的程序,它的作用是加载内核并将控制权交给内核。BootLoader通过读取内核映像文件,将其加载到内存中,然后跳转到内核的入口地址,使内核开始执行。

内核:内核是操作系统的核心部分,它负责管理系统的进程、内存、设备驱动等核心功能。在内核启动后,它会检查文件系统并挂载根文件系统到系统中。

根文件系统:根文件系统是操作系统的文件系统,它包含了操作系统的基本文件和目录。在内核启动后,它会检查文件系统并挂载根文件系统到系统中,使应用程序能够访问和操作这些文件和目录。

在操作系统的启动过程中,BootLoader会加载内核并将控制权交给内核,内核会初始化系统的各个组件,然后检查和挂载根文件系统到系统中。这样,应用程序就可以通过根文件系统访问和操作文件和目录。因此,BootLoader、内核和根文件系统之间的关系是相互依存、缺一不可的。

7、Bootloader启动过程

推荐博客地址:http://t.csdn.cn/e8hzp

8、Linux下检查内存状态的命令

在Linux下,可以使用以下命令来检查内存状态:

free命令:可以显示系统内存状态,包括物理内存、已使用的内存、空闲内存、缓存等。

vmstat命令:可以显示虚拟内存状态,包括内存使用情况、缓存、进程状态等。

top命令:可以实时查看系统内存使用情况,包括内存使用率、进程状态、CPU使用率等。

htop命令:可以以更为详细的格式显示系统内存使用情况,包括每个进程的内存使用情况、CPU使用率等。

sar命令:可以生成系统性能报告,包括内存使用情况、CPU使用率、磁盘使用情况等。

dstat命令:可以显示系统运行状态,包括内存使用情况、CPU使用率、磁盘使用情况等。

这些命令可以帮助用户实时查看系统内存状态,并对系统性能进行监控和分析。

9、大小端的区别以及各自的优点,哪种时候用。(判断大小端的三种方式)

大小端(Endian)是指计算机在存储和表示数据时,对于多字节的数据类型(如整数、长整数等),以不同的字节顺序进行存储和表示。

大端(Big-Endian)表示将数据的高位字节存储在低地址处,而低位字节存储在高地址处。

小端(Little-Endian)表示将数据的低位字节存储在低地址处,而高位字节存储在高地址处。

以下是一些关于大小端的优点和适用场景:

优点:

对于网络传输和跨平台通信,使用小端可以减少数据在不同平台之间的转换次数,提高传输效率。
对于大多数应用程序来说,使用小端可以减少内存的使用,因为低位字节可以更早地被释放掉。
对于一些特定的算法和数据结构,使用小端可以提高数据的局部性,从而提高缓存的命中率。
适用场景:

对于需要跨平台传输数据的应用程序,例如网络通信、分布式系统等,建议使用小端。
对于需要处理大量整数或浮点数运算的应用程序,例如科学计算、图形处理等,建议使用大端。
对于需要处理大量字符串操作的应用程序,例如文本编辑器、编译器等,建议使用小端。
判断大小端的方式有以下三种:

编写一个多字节的数据类型(例如int、long、float或double),并将其存储到内存中。然后,读取内存中的数据,并逐字节地检查它们的值,以确定字节顺序。
使用C标准库中的函数,例如htonl(主机字节序)和ntohl(网络字节序),将一个整数从主机字节序转换为网络字节序,或将网络字节序转换为主机字节序。通过比较转换前后的值来确定字节顺序。
读取和处理操作系统提供的系统寄存器或寄存器映射,以确定字节顺序。不同的处理器架构可能有不同的方式来读取和处理这些寄存器。
需要注意的是,不同的处理器架构可能具有不同的字节顺序,因此在进行跨平台通信或处理不同架构的数据时,应该特别注意字节顺序的问题。

10、一个程序从开始运行到结束的完整过程(四个过程)

1、编译预处理:处理伪指令

  1> 头文件包含

  2> 宏定义

  3> 条件编译   #if #endif  

                 gcc -E xxx.c -o  xxx.i               

2、编译:把预处理之后的文件进行语法分析,生成汇编代码

                 gcc  -S xx.i -o xx.s

3、汇编:将汇编文件生成机器代码(二进制代码)

                 as xx.s -o xx.o

4、链接:去指定路径下找库函数 (头文件包含的是声明,具体实现封装在库中)

                 gcc xx.o -o xx

11、什么是堆,栈,内存泄漏和内存溢出? 

堆(Heap)和栈(Stack)是计算机内存管理中的两个重要概念,而内存泄漏和内存溢出则是与内存管理相关的两个问题。

堆(Heap):堆是一种动态分配的内存区域,它由程序员分配和释放。堆的大小受系统限制,通常位于栈的顶部。在程序运行过程中,当需要分配大块内存时,可以通过调用malloc等函数从堆中分配。堆的优点是可以灵活地分配和释放内存,但需要注意的是,由于堆是动态分配的,可能会存在内存碎片和内存泄漏的问题。

栈(Stack):栈是一种静态分配的内存区域,它由系统自动分配和释放。栈的大小也受系统限制,通常位于内存的底部。在程序运行过程中,当需要分配局部变量或函数参数时,系统会自动从栈中分配内存。栈的优点是分配和释放内存的速度较快,但缺点是空间有限且大小固定,无法分配大块内存。

内存泄漏(Memory Leak):内存泄漏指的是程序中的某些代码由于某些原因未能释放已经不再需要的内存,导致内存无法被再次使用。这通常会导致程序运行过程中出现内存不足的情况,从而导致程序性能下降或崩溃。

内存溢出(Out of Memory):内存溢出指的是程序在运行过程中所需的内存超过了系统所能提供的内存大小。这通常会导致程序崩溃或出现不可预测的行为。为了解决内存溢出问题,程序员需要优化程序的内存使用,避免无谓的内存占用和泄漏。

综上所述,堆、栈、内存泄漏和内存溢出是计算机内存管理中的重要概念。程序员需要合理地使用堆和栈,避免内存泄漏和

12、堆和栈的区别 

堆(Heap)和栈(Stack)是计算机内存管理中的两个重要概念,它们有以下区别:

分配方式:堆是动态分配的,而栈是静态分配的。在程序运行过程中,当需要分配大块内存时,可以通过调用malloc等函数从堆中分配,而栈则是在程序编译时就已经分配好的。

大小限制:栈的大小是有限的,而堆的大小受系统限制。栈通常位于内存的底部,大小固定,而堆位于栈的顶部,可能会占用系统的大部分内存。

内存释放:堆的内存释放需要手动进行,而栈的内存由系统自动释放。在程序运行过程中,如果需要释放堆中的内存,需要手动调用free函数,而栈中的内存会自动释放。

使用场景:栈通常用于存储局部变量、函数参数和返回地址等,而堆通常用于存储动态创建的数据结构和对象。

需要注意的是,由于堆是动态分配的,可能会存在内存碎片和内存泄漏的问题。同时,由于栈的大小有限制,如果分配过多的局部变量或递归调用导致栈溢出的问题也可能出现。

综上所述,堆和栈在分配方式、大小限制和内存释放方面存在明显的区别。程序员需要合理地使用堆和栈来满足程序的需求,避免内存泄漏和溢出问题。

13、死锁的原因、条件 

死锁的原因主要有以下几个:

系统资源不足。在这种情况下,进程的资源请求可能无法得到满足,导致死锁。
进程运行推进的顺序不合适,或者由于进程运行推进顺序与速度不同,也可能导致死锁。
资源分配不当也是死锁的原因之一。
产生死锁的四个必要条件如下:

互斥条件:一个资源每次只能被一个进程使用。
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
只要上述条件之一不满足,就不会发生死锁,而只要系统发生死锁,这些条件必然成立。

14、硬链接与软链接的区别

硬链接和软链接在以下几个方面存在区别:

链接原理:硬链接是指通过文件索引节点(inode)进行的链接,而软链接(也叫符号链接)则是指通过文件路径进行的链接。
链接范围:硬链接仅能在同一文件系统内创建,而软链接可以跨越不同的文件系统。
文件名和文件路径:硬链接保持文件名不变,但文件路径可以自由更改,而软链接实际上是对文件的一个快捷方式,更改软链接的文件路径不会影响原始文件。
文件大小:硬链接和原始文件具有相同的大小,而软链接则保存了文件路径的长度。
创建方式:在Linux系统中,可以使用ln命令创建硬链接和软链接。创建硬链接时,需要使用-l选项,而创建软链接时,需要使用-s选项。
颜色区分:在Linux系统中,硬链接的文件名通常是白色的,而软链接的文件名则是蓝色的。
总结来说,硬链接和软链接在功能上有明显的区别。硬链接强调文件数据块的一致性,可以在不同的目录中创建相同的文件的多个副本,而软链接则强调指向文件的路径,可以跨越不同的文件系统。

15、虚拟内存,虚拟地址与物理地址的转换

虚拟内存是一种计算机内存管理技术,它将计算机的物理内存与硬盘上的虚拟内存结合起来,通过将部分硬盘空间作为内存来使用,从而实现扩大内存的效果。

在虚拟内存中,每个进程都有其独立的虚拟地址空间,用于存储进程的数据和代码。虚拟地址是进程用来访问内存的地址,它与物理地址不同,虚拟地址需要通过虚拟内存管理模块进行转换,才能与物理地址相对应。

虚拟地址通常包括两部分:基址和偏移量。基址是虚拟地址的起始值,而偏移量则是进程中某个数据或指令在虚拟地址中的位置。通过将基址和偏移量相加,可以得到进程在虚拟地址空间中的实际位置。

在虚拟内存中,为了将虚拟地址转换为物理地址,需要使用页表这个数据结构。页表记录了进程的虚拟地址和对应的物理地址之间的映射关系。当进程访问虚拟地址时,操作系统会根据页表中的映射关系,将虚拟地址转换为物理地址,并将数据从磁盘上的虚拟内存映射到物理内存中。

总结来说,虚拟内存、虚拟地址和物理地址之间的转换是通过页表实现的。通过将虚拟地址与页表中的映射关系相加,可以得到对应的物理地址,从而实现虚拟地址到物理地址的转换。(Linux貌似是通过内存管理单元MMU进行虚拟映射的!)

16、计算机中,32bit与64bit有什么区别

计算机的位数一般指操作系统的位数,32位操作系统可以寻址2的32次方个字节的内存范围,而64位操作系统则可寻址2的64次方个字节的内存范围。以下是它们的主要区别:

数据处理能力:32位计算机的CPU一次最多能处理32位数据,例如它的EAX寄存器就是32位的,而64位计算机一次可以处理8个字节,因此64位计算机数据处理能力更强,速度更快。
内存容量支持:32位的系统许多支持4G的内存,而64位系统则可以支持上百G的内存。
软件运行版本:64位的系统能够兼容32位的软件,但32位的系统不能向上兼容。
应用场景:由于64位数据处理能力更强,因此适合处理大规模数据运算和复杂任务,如大型数据库、虚拟化和科学计算等应用场景。而32位系统则更适合于小规模数据处理和简单任务,如Web浏览、电子邮件和轻度办公等应用场景。
总的来说,64位计算机相比32位计算机具有更强的数据处理能力和更大的内存支持,适用于大规模数据运算和复杂任务。而32位计算机则适用于小规模数据和简单任务。同时,64位操作系统也提供了更高的安全性。

17、中断和异常的区别

中断(Interrupt)和异常(Exception)在含义和本质上存在明显区别。

中断:是指系统停止当前正在运行的程序,以便处理其他紧急事件或请求。中断通常是由硬件设施引发的,例如,当处理器检测到硬件故障(如输入/输出设备)或软件优先级较高的请求(如控制台输入)时,会触发中断。中断被视为一种正常现象,因为其目的是为了使系统能够有效地处理各种紧急事件,以保证系统正常运行。
异常:与中断不同,异常是由于软件错误而引起的。异常通常是在程序运行过程中发生的,可能是由于程序本身的错误,或者是由于程序运行过程中出现了一些未被预料到的状况。
总的来说,中断和异常在本质上都是为了处理紧急事件或请求,但中断主要是由于硬件设施或高优先级的软件请求,而异常则主要是由于程序本身运行过程中发生的错误。

18、 Linux 操作系统挂起、休眠、关机相关命令

 在 Linux 操作系统中,挂起、休眠和关机相关的命令主要如下:

挂起(suspend):挂起是一种省电模式,系统将机器的硬盘、显示器等外部设备停止工作,而 CPU 和内存仍然工作,等待用户随时唤醒。在挂起状态下,所有运行的程序和进程都会被暂停,而系统的状态和数据也会被保存在内存中。要挂起系统,可以使用以下命令:sudo pm-suspend。
休眠(hibernate):休眠是一种更加省电的模式,它将内存中的数据保存于硬盘中,使 CPU 也停止工作。在休眠状态下,系统的状态和数据会被完整保存,并且可以随时恢复到休眠前的状态。要休眠系统,可以使用以下命令:sudo pm-hibernate。
关机(shutdown):关机是将计算机系统关闭,停止所有进程和活动。关机通常会关闭所有外部设备,包括电源和磁盘。要关机可以使用以下命令:sudo shutdown -h now。
需要注意的是,这些命令需要在具有 root 权限的环境下执行。另外,不同的 Linux 发行版可能会有一些命令上的差异,具体操作还需参考对应的发行版说明文档。

19、编译优化选项-o

在 Linux 系统中,GCC 编译器提供了多种编译优化选项,其中 -o 是一个用于指定输出文件名的选项。以下是关于编译优化选项 -o 的详细说明:

-o:该选项用于指定输出文件的名称。在编译过程中,GCC 编译器会将生成的目标文件保存为一个文件,该文件的名称可以是任意的,通过 -o 选项可以指定输出文件的名称。例如,gcc -o myprogram mysource.c 表示将 mysource.c 文件编译为名为 myprogram 的可执行文件。
-O:这个选项用于启用编译优化。通过该选项,GCC 编译器会在生成目标代码时进行一些优化操作,以提高代码的运行效率。优化的程度可以通过后续的数字参数来指定,例如 -O1、-O2、-O3 等。
以下是一些常用的编译优化选项:

-O0:禁用所有优化选项,以最小的编译时间生成目标代码。
-O1:启用一些基本的优化选项,主要优化代码大小和运行速度,但不会对编译时间产生太大的影响。
-O2:启用更多的优化选项,除了基本的优化外,还会采用更多的优化算法以提高代码的运行效率。
-O3:启用更多的优化选项,除了基本的优化外,还会采用更多的优化算法以提高代码的运行效率,并可能增加编译时间。
-Os:该选项用于优化代码尺寸,会启用一些能够减小目标代码大小的优化选项,但不会对运行效率产生太大影响。
需要注意的是,不同的编译优化选项可能会对编译时间和生成代码的大小和运行效率产生不同的影响。因此,在实际使用时需要根据具体需求和系统资源进行选择。另外,具体的编译优化选项可能会因 GCC 版本的不同而有所差异,需要参考相应的文档进行选择和使用。

20、 在有数据 cache 情况下,DMA 数据链路为:外设-DMA-DDR-cache-CPU,CPU 需要对 cache 做什么操作,才可以得到数据

在有数据cache的情况下,DMA数据链路为:外设-DMA-DDR-cache-CPU。为了使CPU能够得到数据,需要进行以下操作:

缓存同步(Cache Coherence):由于数据可能已经被缓存在cache中,因此需要确保cache和DDR内存中的数据保持一致。这可以通过使用缓存同步协议来实现,例如MESI(Modified, Exclusive, Shared, Invalid)或MOESI(Modified, Owner, Exclusive, Shared, Invalid)协议。缓存同步的目的是确保CPU在任何时候都能够正确地访问到最新的数据。
数据更新(Data Update):如果数据已经在DDR内存中更新,但cache中仍保持着旧的数据,那么CPU需要确保能够获取到最新的数据。这可以通过在缓存同步过程中使用写回(Writeback)策略来实现,即将cache中过时的数据写回DDR内存,从而保证数据的正确性。
数据访问(Data Access):当CPU需要访问数据时,它会首先检查cache中是否存在所需的数据。如果cache中存在,则可以直接从cache中获取数据,而不需要访问DDR内存。如果cache中不存在所需的数据,则需要进行内存访问,从DDR内存中读取数据。
总之,在有数据cache的情况下,CPU需要对cache进行缓存同步、数据更新和数据访问操作,以确保能够在正确的时机获取到数据。这些操作通常由硬件自动处理,而不需要用户的显式干预。

21、Linux中改变文件属性的命令: chmod

在Linux中,改变文件属性的命令是chmod。chmod命令用于修改文件的访问权限,控制用户或用户组对文件的访问权限。

chmod命令的用法如下:chmod [选项] [模式] 文件名

作者建议当运行某个文件时出现权限不够的情况,直接使用chmod 777 [文件名]

22、Linux中查找文件中匹配字符串的命令: grep 

 在 Linux 中,查找文件中匹配字符串的命令是 grep。grep 命令用于在文件中搜索指定的文本模式,并输出匹配的行。

grep 命令的用法如下:grep [选项] [匹配模式] 文件名

其中,选项可以是以下之一:

-c:只输出匹配行的计数。
-i:忽略大小写,即匹配模式中的字符不区分大小写。
-n:在匹配的行前面输出行号。
-r 或 -R:递归地在目录下查找匹配的行。
-v:输出不匹配的行。
匹配模式是一个正则表达式,用于指定需要匹配的文本模式。例如,以下命令将在文件 test.txt 中查找所有包含字符串 "hello" 的行,并将它们输出到终端:

grep "hello" test.txt

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值