1.如何查看Linux系统中安装的软件包
dpkg --list
在CentOS系统中,可以使用以下命令查看已安装的软件包:
yum list installed
2.如何查看Linux系统的CPU占用率?
top:该命令会打印出系统正在运行的进程和相应的资源占用情况,包括CPU占用率、内存占用率等
3.如何查看Linux系统的磁盘使用情况?
可以使用以下命令查看Linux系统的磁盘使用情况:df
该命令会打印出系统中每个文件系统的使用情况,包括已用空间、剩余空间等。
4.如何查看Linux系统的网络连接情况?
netstat:该命令会打印系统中当前的网络连接状态,包括建立的连接、监听的端口等。
5.如何在Linux系统中安装软件包?
yum install <package_name>
6.如何在Linux系统中检查系统日志?
可以使用以下命令查看Linux系统的系统日志:
tail /var/log/syslog
该命令会打印出系统的系统日志,包括系统重要事件、错误信息等。
7.Linux有哪些系统日志文件?
比较重要的是/var/log/messages日志文件。
8.什么是交换空间?
交换空间是Linux使用的一定空间,用于临时保存一些并发运行的程序。当RAM没有足够的内存来容纳正在执行的所有程序时,就会发生这种情况。
9.什么是LILO?
LILO是Linux的引导加载程序。它主要用于将Linux操作系统加载到主内存中,以便它可以开始运行。
10.什么是inode?
储存文件元信息的区域叫做inode,索引节点的意思。
11.什么是硬链接和软链接?
(1)硬链接由于Linux下的文件是通过索引节点来识别文件,硬链接可以认为是一个指针,指向文件索引节点的指针,系统并不为它重新分配inode。每增加一个一个硬链接,文件的链数就加一。
软链接克服了硬链接的不足,没有任何文件系统的限制,任何用户可以创建指向目录的符号链接。因而现在更为广泛使用,它具有更大的灵活性,可以跨越不同机器、不同网络对文件进行连接。
硬链接不可以跨分区,软链接可以。硬链接指向一个inode节点,而软链接则是创建一个新的inode节点。删除硬链接文件,不会删除源文件,删除软链接文件,会把源文件删除。
12.RAID是什么?
RAID全称为独立磁盘冗余阵列,基本思想就是把多个相对便宜的硬盘组合起来,成为一个硬盘阵列组,使性能达到甚至超过一个价格昂贵、容量巨大的硬盘。
13.系统调用与库函数的区别?
系统调用是程序向系统内核请求服务的方式。可以包括硬件相关的服务,或者创建新进程,调度其他进程等。系统调用是程序和操作系统之间的重要接口。
库函数:把一些常用的函数编写完放到一个文件里,编写应用程序时调用。
14.段页式内存管理有何优点?
段页式内存管理结合了段式内存管理和页式内存管理的优点,提供了灵活性、保护性、共享性和虚拟化支持。
灵活性:将内存划分为段和页的组合,既可以方便地管理不同类型的程序和数据,又可以细致地进行内存分配和利用。
保护性:通过设置段和页的访问权限,可以对内存进行精细的访问控制,保护数据的安全性。
共享性:段页式内存管理支持多个程序共享同一段或同一页面,减少内存重复存储,提高内存利用效率。
15.系统调用read( )/write( ),内核具体做了什么?
- 用户空间发起read()/write()系统调用,并将参数传递给内核。
- 内核根据系统调用号找到相应的内核函数进行处理,如sys_read()/sys_write()。
- 内核根据文件描述符找到对应的文件对象,并执行读取或写入操作。
- 在读取操作中,内核将数据从文件或设备读取到内核空间,并通过页缓存层进行管理。
- 在写入操作中,内核将数据从用户空间拷贝到内核空间,并通过文件系统层将数据写入文件或设备。
- 内核可能会通过缓存管理、块设备管理和驱动程序等层次对数据进行处理和传输。
16.static的作用是什么?
- 在函数内部声明的静态变量:使用 static 关键字声明的局部变量,会在第一次执行到它们时进行初始化,并且在程序运行期间保持存在。这意味着即使离开了其作用域,下次再进入时仍然可以访问该变量的值。
- 在全局范围内声明的静态变量和函数:使用 static 关键字修饰全局变量或者函数,将它们的可见性限制在定义它们的源文件内部。这样做可以避免与其他文件中同名的全局符号冲突。
- 在类中声明的静态成员:使用 static 关键字修饰类成员,使得该成员属于整个类而不是对象实例。静态成员被共享并且只有一份副本,可以通过类名直接访问。
17.全局变量和局部变量在内存中是否有区别?如果有,是什么区别?
- 存储位置:全局变量在程序的数据段或静态数据区中分配内存,而局部变量通常在栈上分配内存。
- 生命周期:全局变量在程序运行期间一直存在,而局部变量只在其所属函数执行期间存在。
- 可见性:全局变量对整个程序可见,可以被不同的函数访问。而局部变量仅在定义它的函数内部可见,其他函数无法直接访问。
- 初始化:全局变量如果没有显式初始化,则会被自动初始化为零值(如整型为0)。而局部变量没有默认初始化值,需要手动赋值或者初始化。
- 内存开销:由于全局变量具有长生命周期,在程序运行期间一直占用内存空间,可能增加内存开销。而局部变量在函数结束时就会释放所占用的栈空间。
18.堆栈溢出一般是由什么原因导致的?
- 递归调用深度过大:如果递归函数的层次过多,每个函数调用都会在栈上分配一定的内存空间,当递归层次太深时,可能会超出栈的容量。
- 局部变量和数组占用过多空间:当函数内定义的局部变量或者数组占用的内存空间过多时,超出了栈的容量限制,就会发生堆栈溢出。
- 函数调用参数传递错误:如果函数调用时传递的参数错误或者参数数量不匹配,可能导致函数内部使用了错误的参数值而引起堆栈溢出。
- 递归调用条件不正确:在递归算法中,没有正确设置终止条件,导致无限循环调用自身而造成堆栈溢出。
- 缓冲区溢出:当输入数据长度超过程序预留缓冲区大小时,写入数据就会超出缓冲区范围,覆盖到相邻内存空间,从而引起堆栈溢出。
19.构造函数生成对象,析构函数释放对象资源
构造函数(Constructor)用于创建对象并初始化其成员变量。当使用类的构造函数时,会为对象分配内存,并执行必要的初始化操作。
析构函数(Destructor)用于释放对象占用的资源,包括动态分配的内存、打开的文件、建立的网络连接等。在对象被销毁时,析构函数会被自动调用,进行资源的清理和释放操作。
构造函数和析构函数是一对特殊的成员函数,在类定义中没有返回类型,并且与类名相同。构造函数通常用于完成对象的初始化工作,而析构函数则负责对象的清理工作。
20.虚函数、纯虚函数、虚函数表
虚函数(Virtual Function)是在基类中声明的可以被派生类重写的函数。它通过使用关键字virtual来进行声明,并且通过指针或引用调用时,会根据实际对象类型调用相应的派生类函数。虚函数使得在运行时能够实现动态绑定(Dynamic Binding),即根据对象的实际类型来确定要调用的函数。
纯虚函数(Pure Virtual Function)是一个在基类中声明但没有具体实现的虚函数。它使用= 0来进行声明,并且表示该函数没有默认的实现,必须在派生类中进行重写。包含纯虚函数的类称为抽象类,不能直接实例化,只能作为基类供其他子类继承。
虚函数表(Virtual Function Table),也称为vtable,是一种用于实现多态性的机制。当一个类含有虚函数时,编译器会生成一个隐藏的指向虚函数表的指针(vptr),并将其作为对象内部成员之一。这个虚函数表记录了该类所有虚函数及其对应的地址,在运行时决定调用哪个版本的虚函数。
21.常见的数据结构
- 数组(Array):由一系列相同类型的元素组成,在内存中连续存储。支持通过索引访问元素,时间复杂度为O(1)。
- 链表(Linked List):由节点组成,每个节点包含一个值和指向下一个节点的指针。可以实现动态插入和删除,但访问需要遍历链表,时间复杂度为O(n)。
- 栈(Stack):先进后出(LIFO)的数据结构,只允许在栈顶进行插入和删除操作。常用于函数调用、表达式求值等场景。
- 队列(Queue):先进先出(FIFO)的数据结构,可以在队尾插入元素,在队头删除元素。常用于任务调度、消息传递等场景。
- 树(Tree):层次结构的非线性数据结构,由节点和边组成。常见的树包括二叉树、二叉搜索树、堆等。
- 图(Graph):由节点和边组成,表示多个对象之间的关系。可以是有向图或无向图。
22.深拷贝和浅拷贝的区别
拷贝的内容:
- 浅拷贝只复制对象的指针或引用,不会创建新的对象副本。因此,原对象和拷贝后的对象会共享同一块内存空间。
- 深拷贝会创建一个全新的独立对象,并将原对象中的所有数据进行复制。这样,在内存中会存在两个完全独立且相同内容的对象。
对象关系:
- 浅拷贝保留了原始对象和拷贝对象之间的关联关系。如果原始对象发生改变,可能会影响到拷贝后的对象。
- 深拷贝破除了原始对象和拷贝对象之间的关联关系。它们在内存中是完全独立、互不干扰的。
内存管理:
- 浅拷贝并不需要额外分配内存,只需简单地复制指针或引用即可。
- 深拷贝需要分配额外内存来保存完整数据副本,并确保对应资源释放时不会出现冲突。
23.多线程如何保证线程安全
- 互斥锁(Mutex):使用互斥锁来实现对共享资源的互斥访问。只有获得锁的线程才能执行临界区代码,其他线程需要等待。
- 读写锁(ReadWrite Lock):适用于读操作远远超过写操作的场景。允许多个线程同时读取共享资源,但在写入时需要独占访问。
- 原子操作(Atomic Operations):使用原子操作可以确保某个操作是不可分割、不会被中断的。常见原子操作包括自增、自减、交换等。
- 条件变量(Condition Variable):用于实现线程间的等待和通知机制。当一个条件不满足时,线程可以等待条件变量;当满足条件时,通过发送信号或广播唤醒等待中的线程。
- 线程安全数据结构:选择已经封装好的线程安全数据结构,如并发队列、并发哈希表等。这些数据结构已经考虑了并发访问下的一致性和同步问题。
- 同步控制:使用同步控制机制来限制对共享资源的访问。如使用信号量、屏障等来协调线程的执行顺序。
- 避免共享数据:尽可能避免多个线程直接访问共享数据,通过消息传递或其他方式来实现线程间的通信。
- 线程安全编程范式:在设计和编写代码时,采用一些线程安全的编程范式,如不可变对象、函数式编程等。
24.struct和class的区别
默认成员访问权限:
- struct:默认的成员访问权限为公共(public)。
- class:默认的成员访问权限为私有(private)。
继承方式:
- struct:默认继承方式为公共继承(public inheritance)。
- class:默认继承方式为私有继承(private inheritance)。
成员函数:
- struct:可以包含成员函数和构造函数。
- class:可以包含成员函数、构造函数、析构函数、拷贝构造函数等。
使用习惯:
- struct:通常用于描述简单的数据结构,并且对成员的访问不加限制。
- class:通常用于面向对象编程中,封装复杂的数据和行为,并通过接口提供对外部使用者的操作。
25.typedef和define的使用
typedef用于创建类型别名。它可以让我们为已有的数据类型(如基本数据类型、结构体、指针等)定义一个新的名称。这样做可以增强代码的可读性和可维护性,也能简化代码书写过程。
而#define用于创建预处理器宏。它会在编译之前将所有出现该宏名称的地方都替换成对应的文本内容。这通常用于定义常量或者带参数的宏函数。