本文是记录平常看到的面试八股文问题,其问题主要是从leetcode中的讨论区整理出来的,答案大多是参考一些大佬讲解来整理的,在此进行整理,方便大家换工作时来熟悉下常见的八股文问题。大家可以看看,也可以讨论下:
//2021.05.10
1、腾讯面试题:寻找一个长度为n+1,且值为1~n的数组中相同的两个元素最优算法
(1)数学加法
(2)异或
腾讯面试题:寻找一个长度为n+1,且值为1~n的数组中相同的两个元素最优算法_zarro brain的博客-CSDN博客
2、malloc和new有以下区别:
(1)new,delete是操作符,只能在C++中使用;
(2)malloc,free是函数,可以覆盖,C,C++中都可以使用;
(3)new可以调用对象的构造函数,对应的delete调用相应的析构函数;
(4)malloc仅仅分配内存,free仅仅回收内存,并不执行构造和析构函数;
(5) malloc/free需要手动计算类型大小且返回值为void*,new/delete可自己计算对应类型的大小。
(6)malloc/free申请空间后得判空,new/delete则不需要。
(7) new直接跟类型,malloc跟字节数个数。
(8)new/delete的底层调用了malloc/free
3、java中new关键字和c++中的new
(1)java中new返回的对像引用,而c++中返回的是对像的实际地址。
没有delete的原因是java有垃圾回收机制,当一个对像没有被引用时,系统会自动将其清理掉(也就是系统自动执行了delete)
4、java中的内存回收机制
(1)
内存泄露:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。
内存溢出:指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,
那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。
(2)
Java 垃圾回收机制原理_wuzhixiu007的博客-CSDN博客_java垃圾回收机制原理
Java 垃圾回收机制整理 - 简书
垃圾回收算法需要做的基本事情:
1)发现无用对象
1.1 引用计数法
1.2 根搜索算法
2)回收被无用对象占用的内存空间,使该空间可被程序再次使用
2.1 标记-清除(Mark-Sweep)算法
2.2 复制(Copying)算法
2.3 标记-整理(Mark-Compact)算法
2.4 分代收集(Generational Collection)算法:
分代收集算法是目前大部分 JVM 的垃圾收集器采用的算法。
核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),
老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法
5、为什么进程切换会比线程切换消耗的资源要多?
进程切换与线程切换的代价比较_c_雨山的博客-CSDN博客_进程间切换比线程间切换开销大
进程切换分两步:
1).切换页目录以使用新的地址空间
2).切换内核栈和硬件上下文
对于linux来说,线程和进程的最大区别就在于地址空间,对于线程切换,第1步是不需要做的,第2是进程和线程切换都要做的。
切换的性能消耗:
(1)、线程上下文切换和进程上下问切换一个最主要的区别是线程的切换虚拟内存空间依然是相同的,但是进程切换是不同的。这两种上下文切换的处理都是通过操作系统内核来完成的。
内核的这种切换过程伴随的最显著的性能损耗是将寄存器中的内容切换出。
(2)、另外一个隐藏的损耗是上下文的切换会扰乱处理器的缓存机制。简单的说,一旦去切换上下文,处理器中所有已经缓存的内存地址一瞬间都作废了。还有一个显著的区别是当你改变虚拟内存空间的时候,
处理的页表缓冲(processor's Translation Lookaside Buffer (TLB))或者相当的神马东西会被全部刷新,这将导致内存的访问在一段时间内相当的低效。但是在线程的切换中,不会出现这个问题。
6、select、poll、epoll之间的区别
select、poll、epoll之间的区别(搜狗面试) - aspirant - 博客园
(1)select==>时间复杂度O(n)
它仅仅知道了,有I/O事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。
所以select具有O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长。
(2)poll==>时间复杂度O(n)
poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态, 但是它没有最大连接数的限制,原因是它是基于链表来存储的.
(3)epoll==>时间复杂度O(1)
epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。所以我们说epoll实际上是事件驱动(每个事件关联上fd)的,
此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1))
select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,
异步I/O的实现会负责把数据从内核拷贝到用户空间。
7、 两个进程分别监听 TCP 和 UDP,可以监听同一个端口?
TCP和UDP可以同时监听相同的端口吗_程序员面试之道的博客-CSDN博客_udp和tcp同时监听一个端口
答:可以,linux是以协议、ip、端口来绑定端口的,所以不同协议相同的ip和端口也是可以绑定成功的
8、Web 页面请求过程(URL请求过程)
浏览器中输入URL,首先浏览器要将URL解析为IP地址,解析域名就要用到DNS协议,首先主机会查询DNS的缓存,如果没有就给本地DNS发送查询请求。DNS查询分为两种方式,
一种是递归查询,一种是迭代查询。如果是迭代查询,本地的DNS服务器,向根域名服务器发送查询请求,根域名服务器告知该域名的一级域名服务器,然后本地服务器给该一级域名服务器发送查询请求,
然后依次类推直到查询到该域名的IP地址。DNS服务器是基于UDP的,因此会用到UDP协议。得到IP地址后,浏览器就要与服务器建立一个http连接。因此要用到http协议,http协议报文格式上面已经提到。
http生成一个get请求报文,将该报文传给TCP层处理。如果采用https还会先对http数据进行加密。TCP层如果有需要先将HTTP数据包分片,分片依据路径MTU和MSS。TCP的数据包然后会发送给IP层,
用到IP协议。IP层通过路由选路,一跳一跳发送到目的地址。当然在一个网段内的寻址是通过以太网协议实现(也可以是其他物理层协议,比如PPP,SLIP),以太网协议需要直到目的IP地址的物理地址,
有需要ARP协议。
//2021.05.12
1、C++中的观察者模式
(1)观察者模式:
是讲有一个目标,众多个观察者去“观察”目标。目标是目标抽象类的一个派生类,观察者是观察者抽象类的一个派生类。当目标类的数据改变,所有对应的观察者对应去更新自己的状态。
注意观察者处于被动地位,被观察者处理主动地位。
(2)应用场景
比如有一个世界时钟程序,有多个图形时钟去显示比如北京时区,巴黎时区,等等。如果设置一个北京时间,那么其他时钟图形都需要更新(加上或者减去时差值)。
典型的图形界面设计随处可见,一个温度程序,在温度湿度等条件改变时,要更新多种显示图形来呈现。
————————————————
版权声明:本文为CSDN博主「developer_wgl」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:c++ 中的观察者模式_developer_wgl的博客-CSDN博客
2、C++中的智能指针实现
智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,
拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;
调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。智能指针就是模拟指针动作的类。所有的智能指针都会重载 -> 和 * 操作符。智能指针还有许多其他功能,
比较有用的是自动销毁。这主要是利用栈对象的有限作用域以及临时对象(有限作用域实现)析构函数释放内存。
C++11中智能指针的原理、使用、实现 - wxquare - 博客园
3、C++模板的偏特化与全特化
(1)模板机制为C++提供了泛型编程的方式,在减少代码冗余的同时仍然可以提供类型安全。 特化必须在同一命名空间下进行,可以特化类模板也可以特化函数模板,但类模板可以偏特化和全特化,
而函数模板只能全特化。 模板实例化时会优先匹配"模板参数"最相符的那个特化版本
C++模板的偏特化与全特化 | Harttle Land
4、C++编译的四个过程
(1)预编译处理(.c) -> 编译、优化程序(.s)->汇编程序(.obj、.o、.a、.ko) -> 链接程序(.exe、.elf、.axf等)
c++程序编译过程 - 知乎
//2021.05.13
1、重载、重写和覆盖的区别
C++中重载、重写(覆盖)和隐藏的区别_走过_冬天的博客-CSDN博客_c 重写和重载
重载:是指同一可访问区内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型
隐藏:是指派生类的函数屏蔽了与其同名的基类函数,注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。
重写(覆盖):是指派生类中存在重新定义的函数。其函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致。只有函数体不同(花括号内),派生类调用时会调用派生类的重写函数,
不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰
2、C++中空类 编译器会自动生成哪些函数
C++空类编译器自动生成的6个成员函数_乌托邦-CSDN博客
答:当空类Empty_one定义一个对象时Empty_one pt;sizeof(pt)仍是为1,
但编译器会生成6个成员函数:一个缺省的构造函数、一个拷贝构造函数、一个析构函数、一个赋值运算符、两个取址运算符。
3、TCP协议-如何保证传输可靠性
网络基础:TCP协议-如何保证传输可靠性_Chenxi13-CSDN博客_tcp如何保证数据传输的可靠性
答:TCP协议保证数据传输可靠性的方式主要有:
校验和
序列号
确认应答
超时重传
连接管理
流量控制
拥塞控制
4、udp如何实现可靠性传输?
udp如何实现可靠性传输?_gettogetto的博客-CSDN博客
UDP它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
传输层无法保证数据的可靠传输,只能通过应用层来实现了。实现的方式可以参照tcp可靠性传输的方式,只是实现不在传输层,实现转移到了应用层。
实现确认机制、重传机制、窗口确认机制。
如果你不利用Linux协议栈以及上层socket机制,自己通过抓包和发包的方式去实现可靠性传输,那么必须实现如下功能:
发送:包的分片、包确认、包的重发
接收:包的调序、包的序号确认
目前有如下开源程序利用udp实现了可靠的数据传输。分别为RUDP、RTP、UDT。
5、拥塞控制和流量控制的区别
TCP流量控制和拥塞控制 - 简单爱_wxg - 博客园
6、如何解决TCP粘包问题
https://blog.csdn.net/m0_37829435/article/details/81747488
(1)设计方案一:定长发送
(2)设计方案二:尾部标记序列
(3)设计方案三:头部标记分步接收
UDP不存在粘包问题
UDP和TCP的区别
TCP和UDP的区别及各自优缺点_随、心所遇 的博客-CSDN博客_tcp和udp的区别
//2021.05.15
1、进程间通信的七种方式:
进程间通讯的7种方式_zhaohong_bo的专栏-CSDN博客_进程间通信
(1)管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
(2)命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
(3)消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
(4)共享存储SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
(5)信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
(6)套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
(7)信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
重要点:采用共享内存进行通信的一个主要好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝,对于像管道和消息队里等通信方式,则需要再内核和用户空间进行四次的数据拷贝(磁盘文件-用户空间-内核空间-用户空间-磁盘文件),
而共享内存则只拷贝两次:一次从输入文件到共享内存区,另一次从共享内存到输出文件。
2、线程间的通信方式
c++ 线程间通信方式_天行九歌-CSDN博客_c++线程间通信
一个进程中的两个线程间通信方式:
(1)互斥锁
mutex;
lock_guard (在构造函数里加锁,在析构函数里解锁)
unique_lock 自动加锁、解锁
atomic 基本类型的原子操作
(2)条件变量condition_variable
关于互斥锁和条件变量:
互斥量可以保护共享数据的修改,如果线程正在等待共享数据的某个条件出现,仅用互斥量的话就需要反复对互斥对象锁定解锁,以检查值的变化,这样将频繁查询的效率非常低。
条件变量可以让等待共享数据条件的线程进入休眠,并在条件达成时唤醒等待线程,提供一种更高效的线程同步方式。条件变量一般和互斥锁同时使用,提供一种更高效的线程同步方式。
(3)信号量
(4)读写锁shared_lock。
3、进程上下文切换的细节
kernel 3.10内核源码分析--进程上下文切换-humjb_1983-ChinaUnix博客
4、中断实现的原理
中断实现的基本原理 - zzfx - 博客园
硬件中断和软件中断的区别_dela_的博客-CSDN博客_硬件中断和软件中断的区别
硬件中断和软中断的区别:
硬件中断是由外设引发的, 软中断是执行中断指令产生的.
硬件中断的中断号是由中断控制器提供的, 软中断的中断号由指令直接指出, 无需使用中断控制器.
硬件中断是可屏蔽的, 软中断不可屏蔽.
硬件中断处理程序要确保它能快速地完成任务, 这样程序执行时才不会等待较长时间, 称为上半部.
软中断处理硬中断未完成的工作, 是一种推后执行的机制, 属于下半部.
5、自旋锁和互斥锁的区别
如何理解互斥锁、条件锁、读写锁以及自旋锁? - 知乎
互斥锁和自旋锁的区别 - TakeTry - 博客园
自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是 否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。其作用是为了解决某项资源的互斥使用。因为自旋锁不会引起调用者睡眠,所以自旋锁的效率远 高于互斥锁。虽然它的效率比互斥锁高,但是它也有些不足之处:
(1)、自旋锁一直占用CPU,他在未获得锁的情况下,一直运行--自旋,所以占用着CPU,如果不能在很短的时 间内获得锁,这无疑会使CPU效率降低。
(2)、在用自旋锁时有可能造成死锁,当递归调用时有可能造成死锁,调用有些其他函数也可能造成死锁,如 copy_to_user()、copy_from_user()、kmalloc()等。
因此我们要慎重使用自旋锁,自旋锁只有在内核可抢占式或SMP的情况下才真正需要,在单CPU且不可抢占式的内核下,自旋锁的操作为空操作。自旋锁适用于锁使用者保持锁时间比较短的情况下。
自旋锁、互斥锁的应用:
互斥锁用于临界区持锁时间比较长的操作,比如下面这些情况都可以考虑
(1) 临界区有IO操作
(2) 临界区代码复杂或者循环量大
(3) 临界区竞争非常激烈
(4) 单核处理器
至于自旋锁就主要用在临界区持锁时间非常短且CPU资源不紧张的情况下,自旋锁一般用于多核的服务器。
6、死锁产生的四个条件
什么是死锁?死锁发生的四个必要条件是什么?如何避免和预防死锁产生?_asrglx8740的博客-CSDN博客
产生死锁的四个必要条件:
● 互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
● 请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
● 不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
● 循环等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
7、Linux中的df、du和tree的区别
Linux中 du (详解)、 df (详解)和 free(详解)以及它们的区别_“花花”公子_龙的博客-CSDN博客
(1) 、du : 显示每个文件和目录的磁盘使用空间~~~文件的大小。
(2)、 df:显示磁盘分区上可以使用的磁盘空间
(3)、free 可以显示Linux系统中空闲的、已用的物理内存及swap内存,及被内核使用的buffer。
8、僵尸进程和孤儿进程
孤儿进程与僵尸进程产生及其处理_Eunice_fan1207的博客-CSDN博客
孤儿进程:父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作
僵尸进程:进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中的这些进程是僵尸进程
避免僵尸进程的方法:
(1)、fork两次用孙子进程去完成子进程的任务
(2)、用wait()函数使父进程阻塞
(3)、使用信号量,在signal handler中调用waitpid,这样父进程不用阻塞
9、创建守护进程
创建守护进程的步骤_mijichui2153的博客-CSDN博客_守护进程
什么是守护进程?
答:守护进程是后台运行的、系统启动是就存在的、不予任何终端关联的,用于处理一些系统级别任务的特殊进程。
创建方法:
(1)fork()创建子进程,父进程exit()退出;
(2)在子进程调用setsid()创建新会话;
(3)再次 fork() 一个子进程,父进程exit退出;
(4)在子进程中调用chdir()让根目录“/”成为子进程的工作目录;
(5)在子进程中调用umask()重设文件权限掩码为0;
(6)在子进程中close()不需要的文件描述符;
(7)守护进程退出处理
10、大端模式和小端模式
大端与小端以及如何判断大小端_qu1993的博客-CSDN博客_如何判断大端和小端
大端:将表示一个对象的字节在内存中按照从最高有效字节到最低有效字节的顺序存储,即最高有效字节在内存地址最前面的方式,称为大端法小端:将表示一个对象的字节在内存中按照从最低有效字节到最高有效字节的顺序存储,即最低有效字节在内存地址最前面的方式,称为小端法
int checkEnd()
{
union
{
long a;
char b
}u;
u.a = 1;
if (u.b == 1) return 0;
else return 1;
}
返回值:大端返回1,小端返回0
11、创建一个线程池
基于C++11实现线程池的工作原理 - 靑い空゛ - 博客园
12、虚拟内存的原理和优点
虚拟内存的原理是什么? - 知乎
虚拟内存原理及其存在意义_Ma_shiro的博客-CSDN博客_虚拟内存的意义
虚拟内存的原理是什么? - 知乎
虚拟内存:
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,
还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型程序的编写变得更容易,
对真正的物理内存(例如RAM)的使用也更有效率
虚拟内存的优点:
(1).虚拟内存将主存看作是在磁盘地址空间上的高速缓存,主存中只保存活动区域并根据需要在磁盘和主存之间来回传送数据
(2).虚拟内存保护每个进程的地址空间不被其他进程破坏
(3).虚拟内存为进程提供了一致的地址空间简化了内存管理
虚拟内存有以下两个优点:
(1).虚拟内存地址空间是连续的,没有碎片
(2).虚拟内存的最大空间就是cup的最大寻址空间,不受内存大小的限制,能提供比内存更大的地址空间
13、库函数调用和内核函数调用的区别
系统调用和库函数调用的区别_leikun153的博客-CSDN博客_系统调用和库函数区别
(1)系统调用是最底层的应用,是面向硬件的。而库函数的调用是面向开发的,相当于应用程序的API(即预先定义好的函数)接口;
(2)各个操作系统的系统调用是不同的,因此系统调用一般是没有跨操作系统的可移植性,而库函数的移植性良好(c库在Windows和Linux环境下都可以操作);
(3)库函数属于过程调用,调用开销小;系统调用需要在用户空间和内核上下文环境切换,开销较大;
(4)库函数调用函数库中的一段程序,这段程序最终还是通过系统调用来实现的;系统调用调用的是系统内核的服务。
系统调用与函数调用的区别:
系统调用
1.使用INT和IRET指令,内核和应用程序使用的是不同的堆栈,因此存在堆栈的切换,从用户态切换到内核态,从而可以使用特权指令操控设备
2.依赖于内核,不保证移植性
3.在用户空间和内核上下文环境间切换,开销较大
4. 是操作系统的一个入口点
函数调用
1.使用CALL和RET指令,调用时没有堆栈切换
2.平台移植性好
3.属于过程调用,调用开销较小
4.一个普通功能函数的调用
14、内核功能和作用
内核功能以及作用_bibizi1987的博客-CSDN博客
(1)内核指的是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。内核是一个操作系统的核心,是操作系统最基本的部分。它负责管理系统的进程、内存、设备驱动程序、
文件和网络系统等,决定着系统的性能和稳定性。它是为众多应用程序提供对计算机硬件的安全访问的一部分软件,这种访问是有限的,并且内核决定一个程序在什么时候对某部分硬件
操作多长时间。直接对硬件操作是非常复杂的,所以内核通常提供一种硬件抽象的方法来完成这些操作。硬件抽象隐藏了复杂性,为应用软件和硬件提供了一套简洁,
统一的接口,使程序设计更为简单。一个内核不是一套完整的操作系统。比如一套基于Linux内核的完整操作系统叫作Linux操作系统,或是GNU/Linux。
(2)
进程管理:内核负责创建和销毁进程, 并处理它们与外部世界的联系(输入和输出),不同进程间通讯(通过信号,管道,或者进程间通讯原语)对整个系统功能来说是基本的,也由内核处理。 另外, 调度器, 控制进程如何共享CPU,是进程管理的一部分。更通常地,内核的进程管理活动实现了多个进程在一个单个或者几个CPU 之上的抽象。
内存管理:计算机的内存是主要的资源, 处理它所用的策略对系统性能是至关重要的。内核为所有进程的每一个都在有限的可用资源上建立了一个虚拟地址空间。内核的不同部分与内存管理子系统通过一套函数调用交互,从简单的malloc/free对到更多更复杂的功能。
文件管理:Linux 在很大程度上基于文件系统的概念;几乎Linux中的任何东西都可看作一个文件。内核在非结构化的硬件之上建立了一个结构化的文件系统,结果是文件的抽象非常多地在整个系统中应用。另外,Linux 支持多个文件系统类型,就是说,物理介质上不同的数据组织方式。例如,磁盘可被格式化成标准Linux的ext3文件系统,普遍使用的FAT文件系统,或者其他几个文件系统。
驱动管理:几乎每个系统操作终都映射到一个物理设备上,除了处理器,内存和非常少的别的实体之外,全部中的任何设备控制操作都由特定于要寻址的设备相关的代码来进行。这些代码称为设备驱动。内核中必须嵌入系统中出现的每个外设的驱动,从硬盘驱动到键盘和磁带驱动器。
网络管理:网络必须由操作系统来管理,因为大部分网络操作不是特定于某一个进程: 进入系统的报文是异步事件。报文在某一个进程接手之前必须被收集,识别,分发,系统负责在程序和网络接口之间递送数据报文,它必须根据程序的网络活动来控制程序的执行。另外,所有的路由和地址解析问题都在内核中实现。
//2021.05.16
1、explicit关键字的作用
C++: explicit的适用场合以及为什么要使用explicit_闭上左眼看世界的博客-CSDN博客
explicit可以抑制内置类型隐式转换,所以在类的构造函数中,最好尽可能多用explicit关键字,防止不必要的隐式转换
2、volatile 关键字的使用场景
volatile 关键字的使用场景及其原理 - king0312的个人空间 - OSCHINA - 中文开源技术交流社区
答:(1)volatile关键字的作用:保证了变量的可见性(visibility)。被volatile关键字修饰的变量,如果值发生了变更,其他线程立马可见,避免出现脏读的现象
(2)volatile只保证线程之间的可见性,不保证同步/互斥性
3、new和mallloc的区别
c++ new 与malloc有什么区别 - ywliao - 博客园
4、如何限制对象只能在堆上创建/如何限制对象只能在栈上创建?
如何限制对象只能建立在堆上或者栈上_舒夜无痕--成为更好的自己-CSDN博客_对象创建限制在堆或栈
(1)只在堆上创建编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存
class A
{
protected:
A(){}
~A(){}
public:
static A* create()
{
return new A();
}
void destory()
{
delete this;
}
}
(2)只在栈上创建
只有使用new运算符,对象才会建立在堆上,因此,只要禁用new运算符就可以实现类对象只能建立在栈上。将operator new()设为私有即可。代码如下:
class A
{
private:
void* operator new(size_t t){} // 注意函数的第一个参数和返回值都是固定的
void operator delete(void* ptr){} // 重载了new就需要重载delete
public:
A(){}
~A(){}
}
5、如何创建出一个类不可以被继承
C++中如何防止类被继承 - Robin Huang - 博客园
c++中虚继承的作用_踏实IT精英的博客-CSDN博客_c++中的虚继承
#include
using namespace std;
template
class Assistant
{
private:
friend T; 9 Assistant(){};
~Assistant(){};
};
class A : public virtual Assistant
{
public:
A(){};
~A(){};
};
class B : public A
{
public:
B(){}:
~B(){};
};
int main(int argc, char* argv[])
{
A a; // 可以构造
B b; // 不能构造
}
6、单例模式和工厂模式——工厂模式稍微有点复杂
http:// https://blog.csdn.net/sinat_33924041/article/details/83621256
7、指针和引用的区别
http:// https://blog.csdn.net/qq_27678917/article/details/70224813
8、如何实现泛型编程 —— 模板,容器实现
C++泛型编程——模板,容器实现_漫鱼-CSDN博客
9、C++ auto 类型推导的原理
https://www.zhihu.com/question/294048058/answer/489015726
(1)auto使用的是模板实参推断(Template Argument Deduction)的机制。auto被一个虚构的模板类型参数T替代,然后进行推断,即相当于把变量设为一个函数参数,将其传递给模板并推断为实参,
auto相当于利用了其中进行的实参推断,承担了模板参数T的作用
(2)而auto类型变量不会是引用类型(模板实参推断的规则),所以要用auto&(C++14支持直接用decltype(auto)推断原始类型),第二个auto推断对应于下面这个模板传参时的情形,
同样T就是为auto推断的类型
(3)唯一例外的是对初始化列表的推断,auto会将其视为std::initializer_list,而模板则不能对其推断
10、C++中的std::initializer_list详解
C++中的std::initializer_list详解_FEEL的博客-CSDN博客_std::initializer_list
std::initializer_list 对象在这些时候自动构造:
(1)用花括号初始化器列表列表初始化一个对象,其中对应构造函数接受一个std::initializer_list 参数
(2)以花括号初始化器列表为赋值的右运算数,或函数调用参数,而对应的赋值运算符/函数接受 std::initializer_list 参数
(3)绑定花括号初始化器列表到 auto ,包括在范围 for 循环中
(4)initializer_list 可由一对指针或指针与其长度实现。复制一个 std::initializer_list 不会复制其底层对象。
11、const和constexpr区别
(1)对于修饰Object来说,const并未区分出编译期常量和运行期常量constexpr限定在了编译期常量然后我想对修饰函数多说两句,那就是constexpr修饰的函数,返回值不一定是编译期常量。
#It is not a bug, it is a feature.#
(2)constexpr修饰的函数,简单的来说,如果其传入的参数可以在编译时期计算出来,那么这个函数就会产生编译时期的值。但是,传入的参数如果不能在编译时期计算出来,
那么constexpr修饰的函数就和普通函数一样了。不过,我们不必因此而写两个版本,所以如果函数体适用于constexpr函数的条件,可以尽量加上constexpr。
而检测constexpr函数是否产生编译时期值的方法很简单,就是利用std::array需要编译期常值才能编译通过的小技巧。
这样的话,即可检测你所写的函数是否真的产生编译期常值了。
12、https的工作原理
HTTPS工作原理 - 五月的仓颉 - 博客园
13、https中客户端为什么信任 证书?
一次看懂 Https 证书认证 - cchao1024 - 博客园
(1)客户端得到服务端返回的证书,通过读取得到 服务端证书的发布机构(Issuer)
(2)客户端去操作系统查找这个发布机构的的证书,如果是不是根证书就继续递归下去 直到拿到根证书。
(3)用 根证书的公钥 去 解密验证 上一层证书的合法性,再拿上一层证书的公钥去验证更上层证书的合法性;递归回溯。
(4)最后验证服务器端的证书是 可信任 的。
14、http中 长连接和短链接的应用场景?
http的长连接和短连接(史上最通俗!)以及应用场景 - 狂风骤起 - 博客园
(1)应用场景:
1)长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,
所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,
而且频繁的socket 创建也是对资源的浪费。
2)像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,
而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。
(2)长连接与短连接区别:
长连接:连接→数据传输→保持连接(心跳)→数据传输→保持连接(心跳)→……→关闭连接(一个TCP连接通道多个读写通信);
短连接:连接→数据传输→关闭连接;
15、ARP攻击和防护方法
ARP 断网攻击的原理是什么?如何完全防护? - 知乎ARP原理和ARP攻击_天行健,君子以自强不息-CSDN博客_arp
16、对称加密和非对称加密
对称加密和非对称加密介绍和区别 - liluxiang - 博客园
(1)对称加密是指加密和解密都使用同一个秘钥; 而非对称加密是有公钥和私钥两个秘钥的.
对称加密速度相对更快,但安全性较低,如果一方的秘钥泄露,那密文就相当于明码了.
而非对称加密速度相对较慢,但安全性更高.(速度我自测过SHA256RSA,签名和验签大约0-10ms,性能也挺高的)
常见的非对称加密算法有:RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用)
17、vector的底层实现
vector的原理与底层实现 - 知道了呀~ - 博客园
主要有四个变量:
T *data; //实际存储数据的数组
size_t _capacity; //容量
size_t _size; //实际元素个数
//扩容
void resize(int st){}
18、当map中的key值 为结构体时,需要重载<号
#include
#include
#include
19、fork()函数的详细情况
fork()创建子进程步骤、函数用法及常见考点