嵌入式面试知识点大全(春秋招必背)

阅读: 评论:0

2024年9月21日发(作者:)

嵌入式面试知识点大全(春秋招必背)

前言

本人蒋豆芽,硕士应届生毕业,也刚好经历完秋招的艰辛,目前已取得满意的offers。

在学习的过程中,自己用心总结了学习的要点,希望帮助到大家!

这份学习指南用最简洁的话语解释每一个知识点,帮助大家以最少的精力学会,省心省

力。

希望大家都能找到满意的工作!谢谢你的支持!

这份学习指南是我用心整理总结出来,包含了本人的心血和原创,希望不要传播。感谢

理解!

嵌入式基础知识

1、CPU的内部架构和工作原理(掌握)

CPU从逻辑上可以划分成3个部分,分别是控制单元、运算单元和存储单元,这三

部分由CPU内部总线连接起来。

控制单元(CU, Control Unit):控制单元是整个CPU的指挥控制中心,由程序计数器

PC (Program Counter)、 指令寄存器IR (Instruction Register)组成。程序计数器包含当前

正在执行的指令的地址,在每个指令被获取之后,程序计数器指向顺序中的下一个指令。

指令寄存器用于暂存当前正在执行的指令。

运算单元(ALU, Arithmetic Logic Unit):是运算器的核心。可以执行算术运算 (包括

加减乘数等基本运算及其附加运算)和逻辑运算 (包括移位、逻辑测试或两个值比较)。

存储单元:包括CPU片内缓存和寄存器组,是CPU中暂时存放数据的地方,里面

保存着那些等待处理的数据,或已经处理过的数据,CPU访问寄存器所用的时间要比访

问内存的时间短。采用寄存器,可以减少CPU访问内存的次数,从而提高了CPU的工

作速度。

总的来说,CPU从内存中一条一条地取出指令和相应的数据,按指令操作码的规定,对数据

图:CPU典型架构图

CPU的运行原理就是:控制单元在时序脉冲的作用下,将程序计数器里所指向的指

令地址送到地址总线上去,然后CPU将这个地址里的指令读到指令寄存器进行译码。对

于执行指令过程中所需要用到的数据,会将数据地址也送到地址总线,然后CPU把数据

读到CPU的内部存储单元(就是内部寄存器)暂存起来,最后命令运算单元对数据进行处

理加工。这个过程不断重复,直到程序结束。

2、CPU的用户态和内核态(掌握)

CPU工作分用户态与内核态。

用户态不能直接使用系统资源,也不能改变CPU的工作状态,并且只能访问这个用

户程序自己的存储空间;内核态可以使用所有的硬件资源。

3、什么是时钟周期?机器周期?指令周期?它们之间的关系?(掌握)

时钟周期又叫做振荡周期;单片机内部时钟电路产生(或外部时钟电路送入)的信

号周期,单片机的时序信号是以时钟周期信号为基础而形成的,时钟周期就是单片机外

接晶振频率的倒数(例如:12M的晶振,它的时钟周期就是1/12us),是计算机中最基本

的、最小的时间单位。在一个时钟周期内,CPU仅完成一个最基本的动作。

机器周期:计算机中,为了便于管理,常把一条指令的执行过程划分为若干个阶段,

每一个阶段完成一项工作。例如:取指令、存储器读、存储器写等,这每一项工作称为

一个基本操作。完成一项基本操作所需要的时间称为机器周期。(例如:对于51单片机,

12M的晶振,它的机器周期是1us)

指令周期:计算机从取一条指令开始,到执行完该指令所需要的时间称为指令周期。

包含若干个机器周期。

4、CPU乱序执行(掌握)

乱序执行(out-of-order execution)是指CPU允许将多条指令不按程序规定的顺序

分开发送给各相应电路单元处理。比方Core乱序执行引擎说程序某一段有7条指令,此

时CPU将根据各单元电路的空闲状态和各指令能否提前执行的具体情况分析后,将能提

前执行的指令立即发送给相应电路执行。

为什么要用乱序执行:本质原因是CPU为了效率,将长费时的操作“异步”执行(如

乘法、除法操作),排在后面的指令不等前面的指令执行完毕就开始执行后面的指令。

而且允许排在前面的长费时指令后于排在后面的指令执行完。

5、什么是MMU(掌握)

MMU(Memory Management Unit)主要用来管理虚拟内存、物理内存的控制线路,同

时也负责虚拟地址映射为物理地址。

如果处理器没有MMU,或者有MMU但没有启用,CPU执行单元发出的内存地址

将直接传到芯片引脚上,被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收,

这称为物理地址(Physical Address,以下简称PA)

如果处理器启用了MMU(一般是在bootloader中的eboot阶段的进入main()函数的

时候启用),CPU执行单元发出的内存地址将被MMU截获,从CPU到MMU的地址

称为虚拟地址(Virtual Address,以下简称VA),而MMU将这个地址翻译成另一个地

址发到CPU芯片的外部地址引脚上,也就是将VA映射成PA

大多数使用MMU的机器都采用分页机制。虚拟地址空间以页为单位进行划分(对

于32位的CPU,通常一页为4k),而相应的物理地址空间也被划分,其使用的单位称

为页帧,页帧和页必须保持相同,因为内存与外部存储器之间的传输是以页为单位进行

传输的。

MMU的作用:一是扩大地址空间,二是内存保护与共享,三是避免内存碎片

6、CPU两种体系结构(掌握)

哈佛结构是一种将程序指令存储和数据存储分开的存储器结构。哈佛结构的微处理

器通常具有较高的执行效率。其程序指令和数据指令分开组织和存储的,执行时可以预

先读取下一条指令。读取指令的同时可以读取数据。

冯·诺伊曼结构也称普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一

起的存储器结构。指令数据按顺序读取。

7、ROM与RAM(掌握)

ROM是只读存储器(Read-Only Memory)的简称,是一种只能读出事先所存数据

的固态半导体存储器。其特性是一旦储存资料就无法再将之改变或删除。

RAM是随机存取存储器(random access memory)又称作“随机存储器”,是与CPU

直接交换数据的内部存储器,也叫主存(内存)。它可以随时读写,而且速度很快。

8、扇区、块、页、簇的概念(掌握)

图:磁盘上的磁道、扇区和簇

每个磁盘有多条同心圆似的磁道,磁道被分割成多个部分。每部分的弧长加上到圆

心的两个半径,恰好形成一个扇形,所以叫做扇区。扇区是磁盘中最小的物理存储单位。

通常情况下每个扇区的大小是512字节。扇面多个同心圆扇区组成。

9、Cache的具体实现(掌握)

Cache是一个高速小容量的临时存储器,可以用高速的静态存储器芯片实现,或者

集成到CPU芯片内部,存储CPU最经常访问的指令或者操作数据。

10、什么是DMA(掌握)

DMA是指外部设备不通过CPU而直接与系统内存交换数据的接口技术。这样数据

的传送速度就取决于存储器和外设的工作速度。DMA的出现就是为了解决批量数据的

输入/输出问题。DMA的一个周期是指存储周期。

11、什么是总线(掌握)

任何一个微处理器都要与一定数量的部件和外围设备连接,但如果将各部件和每一

种外围设备都分别用一组线路与CPU直接连接,那么连线将会错综复杂,甚至难以实现。

为了简化硬件电路设计、简化系统结构,常用一组线路,配置以适当的接口电路,与各

部件和外围设备连接,这组共用的连接线路被称为总线。

微机中总线一般有内部总线、系统总线和外部总线。

内部总线:内部总线是微机内部各外围芯片与处理器之间的总线,用于芯片一级的

互连

(1)I2C:半双工同步串行,双向、两线、速率不快,具有总线仲裁机制,非常适

合器件间近距离经常性数据通信,可实现设备组网;SCL(时钟线)和SDA(数据线),

以地址选择从机,I2C通信的时候,通信双方地位是不对等的,而是分为主设备和从设

备。通信由主设备发起,由主设备主导,从设备只是按照I2C协议被动的接收主设备的

通信,并及时响应。标准模式下可达100kbit/s,快速模式下可达400kbit/s。

(2)SPI:全双工同步串行总线,收发独立,同步接口,可实现多个SPI设备互联,

硬件3~4线;由一个主设备和多个从设备组成,由四跟信号线组成:SDI(串行数据输

入)、SDO(串行数据输出)、SCK(串行移位时钟)、CS(从使能),从设备使能信

号,由主设备控制。

(3)串行通信接口SCI是一种通用异步通信接口UART。

(4)UART:通用全双工异步串行口,速率不快,由波特率产生器、UART发送器、

UART接收器组成,硬件上两线,一收一发;主机和从机至少要接三根线,RX(接收)、

TX(发送)和GND。

系统总线:系统总线是微机中各插件板与系统板之间的总线,用于插件板一级的互

(1)ISA总线:

(2)EISA总线:

(3)VESA总线:

(4)PCI总线:

外部总线:外部总线则是微机和外部设备之间的总线

(1)RS-232总线:RS-232总线规定了25条线,在一般应用中,使用3条~9条信

号线就可以实现全双工通信,采用三条信号线(接收线、发送线和信号地)能实现简单

的全双工通信过程。RS-232可以灵活地适应不同速率的设备。实际工作时,应保证电平

在-3V~-15V或+3V~+15V之间,RS323是一种通讯标准, 因为高电平+15V低电平-15V

电位差30V容错空间大,抗干扰能力强,一般用于工业设备直接通信电平转换芯片一般

有MAX3232,SP3232。TTL一般是从单片机或者芯片中发出的电平,高电平为5V(51

单片机)或者3.3V(stm32)。

(2)RS-485总线:采用半双工工作方式,支持多点数据通信。RS-485采用平衡发

送和差分接收,因此具有抑制共模干扰的能力。通信距离可为几十米到上千米。

(3)USB总线:USB总线是为通用串行总线,USB接口位于PS/2接口和串并口之

间,允许外设在开机状态下热插拔,最多可串接下来127个外设,传输速率可达480Mb/S,

它可以向低压设备提供5伏电源,同时可以减少PC机I/O接口数量。

12、RS232接口与RS485的区别(掌握)

由于RS232接口标准出现较早,难免有不足之处,主要有以下四点:

(1) 接口的信号电平值较高,易损坏接口电路的芯片,又因为与TTL 电平不兼容

故需使用电平转换电路方能与TTL电路连接。

(2) 传输速率较低,在异步传输时,波特率为20Kbps。

(3) 接口使用两根信号线和一根地线返回而构成共地的传输形式,容易产生共模

干扰,所以抗噪声干扰性弱。

(4) 传输距离有限,最大传输距离标准值为50英尺,实际上也只能用在50米左

右。

针对RS232接口的不足,于是就不断出现了一些新的接口标准,RS-485就是其中之

一,它具有以下特点:

(1) RS-485的电气特性:逻辑“1”以两线间的电压差为+(2-6) V表示;逻辑

“0”以两线间的电压差为-(2-6)V表示。接口信号电平比RS-232降低了,就不易损

坏接口电路的芯片,且该电平与TTL电平兼容,可方便与TTL 电路连接。

(2) RS-485的数据最高传输速率为10Mbps 。

(3) RS-485接口是采用平衡驱动器和差分接收器的组合,抗共模干能力增强,即

抗噪声干扰性好。

(4) RS-485接口的最大传输距离标准值为4000英尺,实际上可达3000米,另外

RS-232接口在总线上只允许连接1个收发器,即单站能力。而RS-485接口在总线上是

允许连接多达128个收发器。即具有多站能力,这样用户可以利用单一的RS-485接口方

便地建立起设备网络。

干扰电压和电流分为两种:一种是两根导线分别做为往返线路传输;另一种是两根

导线做去路,地线做返回路传输。前者叫“差模”,后者叫“共模”。

13、UART与USART的区别(掌握)

UART与USART都是单片机上的串口通信,他们之间的区别如下:

UART:universal asynchronous receiver and transmitter通用异步收/发器

USART: universal synchronous asynchronous receiver and transmitter通用同步/异步收/

发器

从名字上可以看出,USART在UART基础上增加了同步功能,即USART是UART

的增强型。

其实当我们使用USART在异步通信的时候,它与UART没有什么区别,但是用在

同步通信的时候,区别就很明显了:大家都知道同步通信需要时钟来触发数据传输,也

就是说USART相对UART的区别之一就是能提供主动时钟。如STM32的USART可以

提供时钟支持ISO7816的智能卡接口。

14、波特率是什么?串行通信对波特率有什么基本要求?波特率高速和低速区别(掌握)

波特率(Baud Rate) 单位 bps -- 每秒传送的字节数 Byte Per Second.

波特率通常单位是bit/s,也就是二进制位/秒。因为一个字节是8个bit,而一个字节

通常可以表达一个ASCII码,比如一个英文字母,所以:9600的波特率的信道,理论上

每秒可以传输9200/8个英文字母的数据量,也就是1200个字节,大约1.2KB。而19200

则是每秒可传输2400字节。

串行通信对波特率的基本要求是互相通信的甲乙双方必须具有相同的波特率。速度

不匹配就会有误差。

低速还是高速不是说波特率多大,而是用来计算初始值的。一般的规格书上都有相

关的公式。

下面是PIC单片机的计算公式:

高速:波特率=fosc/16*(x+1) (fosc代表外部晶振)

低速:波特率=fosc/64*(x+1)

15、异步串行和同步串行(掌握)

异步位系统是面向字符来传输信息的,也就是我们一般情况下的一个字符,8位,

1bit,当然了传输的时候还要加上起始位和结束位,没有这两位接收方就不知道什么时候

开始接收数据什么时候结束了。如此一来字符与字符之间就不是连着的,打个比喻,就

像秋天的叶子一样,一片一片往下落。发送方和接收方不要求同步,就是说你想什么时

候落就什么时候落,我都接着,用不着先通知我

同步位系统就不同了,他要求发送方与接收方严格的同步,二者波特率要相同。

通信双方共用一个时钟,这是同步通信区分于异步通信的最显著的特点。在异步通信中,

每个字符要用起始位和停止位作为字符开始和结束的标志,以致占用了时间。所以在数

据块传送时,为提高通信速度,常去掉这些标志,而采用同步通信。同步传送时,字符

之间没有间隙,也不要起始位和停止位,仅在数据开始时用同步字符SYNC来指示。这

里再打个比喻,前面我们说异步位系统传输的数据像树叶,那么同步位系统传输的就像

是把这些树叶串成一串,是连续的。

16、CAN总线介绍(掌握)

CAN(Controller Area Network)即控制器局域网,是一种能够实现分布式实时控制

的串行通信网络。

(1)可以多主方式工作,网络上任意一个节点均可以在任意时刻主动地向网络上的

其他节点发送信息,而不分主从,通信方式灵活。

(2)网络上的节点可分成不同的优先级,可以满足不同的实时要求。

(3)采用非破坏性位仲裁总线结构机制,当两个节点同时向网络上传送信息时,优

先级低的节点主动停止数据发送,而优先级高的节点可不受影响地继续传送数据。

(4)可以点对点,一点对多点及全局广播几种传送方式接收数据。

(5)直接通信距离最远可达10km

(6)通信速率最高可达1MB/s

CAN总线仲裁机制

CAN总线为多主工作方式,网络上任意一节点均可在任意时刻主动向网络上的其它

节点同时发送消息。若两个或两个以上的节点同时开始传送报文,就会产生总线访问冲

突,根据逐位仲裁原则,借助帧开始部分的标识符,优先级低的节点主动停止发送数据,

而优先级高的节点继续发送信息。在仲裁期间,CAN总线作“与”运算,每一个节点都

对节点发送的电平与总线电平进行比较,如果电平相同,则节点可以继续发送。如规定

0 的优先级高,当某一个节点发送1而检测到0 时,此节点知道有更高优先级的信息在

发送,它就停止发送消息,直到再一次检测到网络空闲。

17、EPROM、EEPROM、Flash(掌握)

EPROM(Erasable Programmable ROM,可擦除可编程ROM)芯片通过紫外线可重复

擦除和写入,解决了PROM芯片只能写入一次的弊端。EPROM芯片在写入资料后,还要以

不透光的贴纸或胶布把窗口封住,以免受到周围的紫外线照射而使资料受损。使用并不方

便。

EEPROM(electrically erasable, programmable, read-only )是一种电可擦除可编程只读

存储器,并且其内容在掉电的时候也不会丢失。在平常情况下,EEPROM与EPROM一

样是只读的,需要写入时,在指定的引脚加 上一个高电压即可写入或擦除,而且其擦除

的速度极快

Flash它的主要特点是在不加电的情况下能长期保持存储的信息。就其本质而言,

Flash Memory属于EEPROM(电擦除可编程只读存储器)类型。它既有ROM的特点,又

有很高的存取速度,而且易于擦除和重写,功耗很小。

18、原码、反码、补码(掌握)

原码:是最简单的机器数表示法。用最高位表示符号位,‘1’表示负号,‘0’表

示正号。其他位存放该数的二进制的绝对值。

反码:正数的反码还是等于原码;负数的反码就是他的原码除符号位外,按位取反。

补码:正数的补码等于他的原码;负数的补码等于反码+1

19、常用的数据校验算法(掌握)

奇偶校验:奇偶校验是检测错误的最古老的方法。用于检查数据传输的完整性。校

验方法非常简单,只需要在数据上添加一个额外的位,这个额外的位称为奇偶校验位。

若用奇校验,则当接收端收到这组代码时,校验“1”的个数是否为奇数,从而确定传输

代码的正确性。对于偶校验,校验位就定义为1;对于奇校验,则相反。

LRC:纵向冗余校验(Longitudinal Redundancy Check,LRC)是一个逐字节奇偶校

验计算,将数据字的所有字节一起异或,创建一个字节的结果,也称为 XOR 校验和

校验和:校验和(checksum)是指传输位数的“累加”(加法操作可能不是普通整

数加法)。奇偶校验和 LRC 可以说是校验和的一种形式(严格意义上来说,他们是异

或,而不是和)。将奇偶校验的思想扩展,将消息中的字节汇总成一个校验字节(而不

是奇偶校验的比特位),这个字节就是校验和

20、驱动设备的类型(掌握)

(1)字符设备。字符设备是能够像字节流(比如文件)一样访问的设备,由字符设

备驱动从程序来实现这种特性,通过/dev/下的字符设备文件来访问。字符设备驱动程序

通常至少需要实现open、close、read和write等系统调用所对应的、对该硬件进行操作

的功能函数。如按键,串口,声卡,触摸屏等

(2)块设备。有缓存来支持,块设备必须能够随机存取(random access),字符设备

则没有这个要求。 UNIX下,采用一个数据块来进行访问,数据块一般为512字节,1K

等,linux下,可以采用任意尺寸的数据来访问。如硬盘、U盘、光盘、SD卡、nandflash

等。

(3)网络设备。在/dev/下没有对应的设备文件,必须通过套接字来访问,要结合

TCP/IP协议栈来使用

典型微处理器

1、ARM处理器(掌握)

ARM(Advanced RISC Machines)是一个32位RISC(精简指令集)处理器架构,

ARM处理器则是ARM架构下的微处理器。ARM处理器广泛的使用在许多嵌入式系统。

ARM处理器的特点有指令长度固定,执行效率高,低成本,低功耗等。ARM内部资源

丰富,外部外设接口丰富,通用性好。

RISC优先选取使用频最高的简单指令,避免复杂指令;将指令长度固定,指令格

式和寻地方式种类减少;以控制逻辑为主。

ARM的基本数据类型

(1)双字节(DoubleWord):64位

(2)字(Word):在ARM体系结构中,字的长度为32位。

(3)半字(Half-Word):在ARM体系结构中,半字的长度为16位。

(4)字节(Byte):在ARM体系结构中,字节的长度为8位。

ARM属于小端模式。

小端模式:低的有效字节存储在低的存储器地址。

大端模式:高的有效字节存储在低的存储器地址。

2、STM32处理器(熟悉)

STM32系列基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM

Cortex-M3内核。

内核:ARM32位Cortex-M3 CPU,最高工作频率72MHz,1.25DMIPSMHz。单周

期乘法和硬件除法。

存储器:片上集成512KB的Flash存储器。6-64KB的SRAM存储器。

低功耗:3种低功耗模式:休眠,停止,待机模式。

调试模式:串行调试(SWD)和JTAG接口。

DMA:12通道DMA控制器。

支持的外设:定时器,ADC,DAC,SPI,IIC和UART。

2个12位的us级的AD转换器(16通道):AD测量范围:0-3.6 V。双采样和保

持能力。片上集成一个温度传感器。

2通道12位DA转换器:STM32F103xC,STM32F103xD,STM32F103xE独有。

最多高达112个的快速IO端口

最多多达11个定时器:

2个看门狗定时器(独立看门狗和窗口看门狗)。

最多多达13个通信接口:2个IIC接口(SMBusPMBus)。5个USART接口(ISO7816

接口,LIN,IrDA兼容,调试控制)。3个SPI接口(18 Mbits),两个和IIS复用。CAN

接口(2.0B)。USB 2.0全速接口。SDIO接口。

3、DSP(掌握)

DSP(digital singnal processor)是一种独特的微处理器,是以数字信号来处理大量

信息的器件。其工作原理是接收模拟信号,转换为0或1的数字信号,再对数字信号进

行修改、删除、强化,并在其他系统芯片中把数字数据解译回模拟数据或实际环境格式。

采用哈佛结构,将程序和数据空间分开,可以同时访问指令和数据;DSP优势在于其有

独特乘法器,一个指令就可以完成乘加运算。并且同时访问指令和数据,大大提高效率。

ARM与DSP的区别:ARM处理器广泛的使用在许多嵌入式系统。ARM处理器的

特点有指令长度固定,执行效率高,低成本,低功耗等。ARM内部资源丰富,外部外

设接口丰富,通用性好。偏重控制。DSP偏重运算,有独特乘法器,一个指令就可以完

成乘加运算,适合于信号、图像等需要大量数字运算的地方。

4、ARM的汇编和8086的汇编有什么区别(掌握)

精简指令集与复杂指令集的区别。RISC优先选取使用频最高的简单指令,避免复

杂指令;将指令长度固定,指令格式和寻地方式种类减少;以控制逻辑为主。

5、单片机的几种寻址方式(掌握)

(1)立即寻址,MOV A, #3AH ; 3AH→A

(2)直接寻址,MOV A, 3AH ; (3AH)→A

(3)寄存器寻址,MOV A,R0 ; (R0 )→A

(4)间接寻址,MOV R1,#30H ; (R1)←立即数30H

MOV @R1,#0FH ; (30H)←立即数0FH

MOV A,@R1 ; (A)←((30H))=#0FH

(5)变址寻址,设:A中已存有#30H,DPTR中已存有#1000H

MOVC A,@A+DPTR; (A)←((A)+(DPTR))

(6)位寻址,CLR P1.0 ; (P1.0) ←0

立即寻址最快,因为指令地址码即为操作数。

6、51单片机(掌握)

51单片机是对所有兼容Intel 8031指令系统的单片机的统称。

(1)8位CPU,4kbytes程序存储器(ROM) (52为8K)

(2)128bytes的数据存储器(RAM) (52有256bytes的RAM)

(3)32条I/O口线(P1,P2,P3,P4),111条指令,大部分为单字节指令

(4)2个可编程定时/计数器,5个中断源,2个优先级(52有6个)

(5)一个全双工串行通信口

(6)单一+5V电源供电

51单片机是大端模式。

7、IO口工作方式(掌握)

四种工作方式:上拉输入、下拉输入、推挽输出、开漏输出

上拉输入:将一个不确定的信号,通过一个电阻与电源VCC相连,固定在高电平。

在IO口为输入模式且为上拉电阻时,IO口的常态为高电平。

下拉输入:将一个不确定的信号,通过一个电阻与地GND相连,固定在低电平。

在IO口为输入模式且为下拉电阻时,IO口的常态为低电平。

推挽输出:可以输出高、低电平,连接数字器件。推挽结果一般是指两个三极管分

别受两互补信号的控制,总是在一个三极管导通时令一个三极管截止。(推挽输出的最

大特点是可以真正的输出高电平和低电平,且两种电平下都有驱动能力)。IO输出0-

接GND, IO输出1 -接VCC

开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要加上拉电阻才行。

适合做电流型的驱动,其吸收电流的能力比较强(20mA左右)(开漏输出最主要的特

性就是高电平没有驱动能力,需要借助外部上拉电阻才能真正输出高电平)。开漏只能

输出低电平,高电平的时候实际上是个高阻态,需要外接电阻来拉高的。

8、浮空和高阻态的区别(掌握)

浮空:浮空就是不接任何器件

高阻态:无上拉和无下拉,对外表现出电平不确定性

把一个端口置为高阻态,相当于该端口从电路中断开(仅对输出来说),比如在一

个通信线上挂了几个端口,将一个端口置为高阻态,就意味着该端口不会影响到该通信

线的电平变化,但还是可以读取端口的电平。一般高阻态都是作为模拟量输入的,因为

高阻态不会影响到输入的电平,可以准确的读取模拟量。

9、中断响应的流程(掌握)

(1)保护断点,即保存下一将要执行的指令的地址,就是把这个地址送入堆栈。

(2)寻找中断入口,在这5个入口地址处存放有中断处理程序。

(3)执行中断处理程序。

(4)中断返回:执行完中断指令后,就从中断处返回到主程序,继续执行。

10、C51编译器支持三种存储模式(掌握)

C51编译器支持三种存储模式:SMALL模式、COMPACT模式和LARGE模式。不

同的存储模式对变量默认的存储器类型不一样。

(1)SMALL模式。SMALL模式称为小编译模式,在SMALL模式下,编译时,

函数参数和变量被默认在片内RAM中,存储器类型为data。

(2)COMPACT模式。COMPACT模式称为紧凑编译模式,在COMPACT模式下,

编译时,函数参数和变量被默认在片外RAM的低256字节空间,存储器类型为pdata。

(3)LARGE模式。LARGE模式称为大编译模式,在LARGE模式下,编译时函

数参数和变量被默认在片外RAM的64K字节空间,存储器类型为xdata。

在程序中变量的存储模式的指定通过#pragma预处理命令来实现。函数的存储模式

可通过在函数定义时后面带存储模式说明。如果没有指定,则系统都隐含为SMALL模

式。

11、data、code、xdata、idata、pdata、bdata(掌握)

data ---> 可寻址片内RAM

bdata ---> 可位寻址的片内RAM

idata ---> 可寻址片内RAM,允许访问全部内部RAM

pdata ---> 分页寻址片外RAM(MOVX @R0) (256 BYTE/页)

xdata ---> 可寻址片外RAM(64k 地址范围FFFFH)

code ---> 程序存储区 (64k 地址范围),对应MOVC @DPTR

12、51单片机里的bit和sbit(掌握)

用bit定义的位变量在C51编译器编译时,在不同的时候位地址是可以变化的,而

用sbit定义的位变量必须与51单片机的一个可以寻址位单元或可位寻址的字节单元中的

某一位联系在一起,在C51编译器编译时,其对应的位地址是不可变化的。

13、C51单片机的IO第二功能(掌握)

14、C51单片机的中断资源(熟悉)

15、看门狗的原理(掌握)

工作原理:在系统运行以后就启动看门狗计数器,此时看门狗就开始自动计时,如

果达到一定的时间还不去给它进行清零,看门狗计数器就会溢出从而引起看门狗中断,

造成系统的复位。

看门狗作用:防止程序死循环和跑飞。

16、什么是交叉编译?为何要有交叉编译(掌握)

交叉编译,就是:在一种平台上编译,编译出来的程序,是放到别的平台上运行即

编译的环境,和运行的环境不一样,属于交叉的,此所谓cross,此所谓:在x86平台上

编译,在ARM平台上运行

之所以要有交叉编译,主要原因是:嵌入式系统中的资源太少。没办法进行本地编译

17、FreeRTOS、uCOS的区别(掌握)

(1)内核ROM和耗费RAM都比uCOS 小,特别是RAM。 这在单片机里面是稀缺资

源,uCOS至少要5K以上, 而freeOS用2~3K也可以跑的很好。

(2)freeRTOS 可以用协程(Co-routine),减少RAM消耗(共用STACK)。uCOS只

能用任务(TASK,每个任务有一个独立的STACK)。

(3)freeRTOS 可以有优先度一样的任务,这些任务是按时间片来轮流处理,uCOSII 每

个任务都只有一个独一无二的优先级。因此,理论上讲,freeRTOS 可以管理超过64个

任务,而uCOS只能管理64个。

(5)freeRTOS 是在商业上免费应用。uCOS在商业上的应用是要付钱的。

freeRTOS 不如uCOS的地方:

(1)比uSOS简单,任务间通讯freeRTOS只支持Queque, Semaphores, Mutex。 uCOS

除这些外,还支持Flag, MailBox.

(2)uCOS的支持比freeRTOS 多。除操作系统外,freeRTOS只支持TCPIP, uCOS则

有大量外延支持,比如FS, USB, GUI, CAN等的支持

18、试描述MQTT、CoAP、HTTP三种协议的区别(掌握)

(1)协议栈:

MQTT: TCP 长链接, CoAP: UDP 低功耗短连接, HTTP: TCP

(2)请求方式

MQTT: 发布订阅, CoAP: request/ response, HTTP: request/ response

(3)通讯消息格式:

(4)使用特点与使用场景

MQTT是多个客户端通过一个中央代理传递消息的多对多协议。它通过让客户端发布消

息、代理决定消息路由和复制来解耦生产者和消费者。虽然MQTT持久性有一些支持,

但它是最好的实时通讯总线。吞吐量更大,MQTT比HTTP快93倍,省流量。

CoAP是受限制的应用协议(Constrained Application Protocol)的代名词。由于目前物联网

中的很多设备都是资源受限型的,所以只有少量的内存空间和有限的计算能力,传统的

HTTP协议在物联网应用中就会显得过于庞大而不适用。因此,IETF的CoRE工作组提

出了一种基于REST架构、传输层为UDP、网络层为6LowPAN(面向低功耗无线局域

网的IPv6)的CoAP协议。

HTTP是适合使用在性能好一些的终端上,相对以上一些比较重,对设备要求相对高一

些。不适合M2M的场景。

C/C++

1、什么是预编译?何时需要预编译?(掌握)

(1)预编译又称预处理,是做些代码文本的替换工作,即程序执行前的一些预处理

工作。主要处理#开头的指令,如拷贝#include包含的文件代码、替换#define定义的宏、

条件编译#if等。

(2)何时需要预编译:

a.总是使用不经常改动的大型代码体;

b.程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。

在这种情况下,可以将所有包含文件预编译为一个预编译头。

2、#define 和 typedef的区别(掌握)

(1)首先,二者执行时间不同

关键字typedef在编译阶段有效,由于是在编译阶段,因此typedef有类型检查的功

能。

define则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的

字符串替换,而不进行任何检查。

(2)作用域不同

#define没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用。

而typedef有自己的作用域。

3、写一个“标准”宏,这个宏输入两个参数并返回较小的一个(掌握)

#define MIN(x, y) ((x) < (y) ? (x) : (y)) //注意结尾没有;C语言面试知识

//注意参数带括号

4、用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)(掌

握)

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL

1). #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)

2). 懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中

有多少秒而不是计算出实际的值,是更清晰而没有代价的。

3). 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告

诉编译器这个常数是的长整型数。

5、用变量a给出下面的定义(掌握)

a) 一个整型数 int a;

b) 一个指向整型数的指针 int *a;

c) 一个指向指针的的指针,它指向的指针是指向一个整型数 int **a;

d) 一个有10个整型数的数组 int a[10];

e) 一个有10个指针的数组,该指针是指向一个整型数的 int *a[10];

f) 一个指向有10个整型数数组的指针 int (*a)[10];

g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数 int (*a)(int);

6、C语言关键字static的作用(掌握)

(1)定义全局静态变量和局部静态变量:在变量前面加上static关键字。都会在数

据段或BSS段分配内存,直到程序结束,因此会维持前值。只不过全局静态变量和局部

静态变量的作用域不一样。

(2)定义静态函数:在函数返回类型前加上static关键字,函数即被定义为静态函

数。静态函数只能在本源文件中使用。

(3)在变量返回类型前加上static关键字,函数即被定义为静态变量。静态变量只

能在本源文件中使用。

7、静态变量什么时候初始化(掌握)

C++规定全局或局部静态对象当且仅当对象首次用到时进行构造

8、源码到可执行文件的过程(掌握)

(1)预处理

1)将所有的“#define”删除,并且展开所有的宏定义

2)处理所有的条件编译指令,如:“#if”、“#ifdef”、“#elif”、“#else”、

“endif”等。这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序

对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉。

3)处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置。

4)删除所有的注释

5)添加行号和文件名标识。

(2)编译

将预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后,产生

相应的汇编代码文件。

(3)汇编

将编译完的汇编代码文件翻译成机器指令,并生成可重定位目标程序的.o文件

(4)链接

将目标文件对应的库链接起来,最后生成可执行文件.exe

静态链接与动态链接的区别:静态链接的过程把要调用的函数或者过程已经链接到

了生成的可执行文件中,就算你在去把静态库删除也不会影响可执行程序的执行;而动

态链接这个过程却没有把调用的函数代码链接进去,而是在执行的过程中,再去找要链

接的函数,生成的可执行文件中没有函数代码,只包含函数的重定位信息,所以当你删

除动态库时,可执行程序就不能运行。

9、什么是字节对齐?为什么要字节对齐?(掌握)

在C语言中,结构体是一种复合数据类型,其构成元素既可以是基本数据类型(如

int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构体、联合体等)

的数据单元。在结构体中,编译器为结构体的每个成员按其自然边界(alignment)分配

空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结

构体的地址相同。

为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所

谓的”对齐”,比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地

址能够被4整除,也即对齐跟数据在内存中的位置有关。如果一个变量的内存地址正好

位于它长度的整数倍,他就被称做自然对齐。

比如在32位cpu下,假设一个整型变量的地址为0x00000004(为4的倍数),那它就

是自然对齐的,而如果其地址为0x00000002(非4的倍数)则是非对齐的。

现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的

访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存

地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接

一个的排放,这就是对齐。

为什么要字节对齐:

需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址

不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第

一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的

一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次

内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。

而如果变量在自然对齐位置上,则只要一次就可以取出数据。一些系统对对齐要求

非常严格,比如sparc系统,如果取未对齐的数据会发生错误,而在x86上就不会出现

错误,只是效率下降。

各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据

只能从某些特定地址开始存取。比如有些平台每次读都是从偶地址开始,如果一个int

型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这

32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高

低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。

10、结构体和联合体有什么区别(掌握)

(1)区别

结构体是多个不同类型变量的组合,其占用的内存大小是所有变量大小的总和

联合体是多个不同类型变量的抽取,其占用内存的大小是联合体中最大的那个变量

的大小

(2)解释

结构体中的多个变量同时存在,你可以给其中的每个变量分别赋值。任何一个变量

被赋值不影响其他变量。你在需要使用时每个变量都可以同时被取出使用。

联合体中的多个变量同时只有一个存在。你只能给其中的一个变量赋值。你在给联

合体的任何一个变量赋值的时候就覆盖了其他的变量,也就是说只有你刚赋值的这个变

量存在,其他都被覆盖掉了

11、const作用(掌握)

const修饰指针的含义:

(1)const int *ptr; ptr指针所指向的内存里的值不变,即(*ptr)不变

(2)int *const ptr; ptr指针所指向的内存地址不变,即ptr不变

(3)const int *const ptr; 都不变,即(*ptr)不变,ptr也不变

const作用:

(1)const修饰变量,const int a:防止被修饰的成员的内容被改变。

(2)const修饰函数参数:表示在函数内部访问参数时(包括指针和实参),值不

会发生变化。

(3)const修饰函数返回值

(4)const修饰函数:表示其为一个常函数,意味着成员函数将不能修改类成员变

量的值。

const数据成员必须使用成员初始化列表进行初始化。

const实现原理:

修饰的变量作为常量可以直接存储在代码段的常量区,这样自然就不能修改了。

12、关键字volatile有什么含意(掌握)

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器每

次会从内存里重新读取这个变量的值,而不是从寄存器里读取。

特别是多线程编程中,变量的值在内存中可能已经被修改,而编译器优化优先从寄

存器里读值,读取的并不是最新值。

13、C语言中的宏(掌握)

宏定义是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件

包含、条件编译。

(1)不带参数的宏定义:

格式: #define 标识符 字符串

预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。

(2)带参数的宏定义:

例如:#define S(a,b) ((a)*(b))

类似于函数功能

宏定义的缺陷:

(1)在预编译阶段暴力替换,不会进行类型检查,并不安全。

(2)在带参数的宏定义中,容易出问题,边界溢出,或表达式没有起作用等

14、C++与C语言的区别(掌握)

设计思想上:

C++是面向对象的语言,而C是面向过程的语言。

性能上:

C是C++的子集。C++在C的基础上增加了很多高级特性。

引入类,使得C++拥有三大特性:重载、继承、封装

C++引入引用的概念,增加了安全的强制类型转换

C++引入STL、类模板、泛型编程。

15、C++中static的作用(掌握)

(1)定义全局静态变量和局部静态变量:在变量前面加上static关键字。都会在数

据段或BSS段分配内存,直到程序结束,因此会维持前值。只不过全局静态变量和局部

静态变量的作用域不一样。

(2)定义静态函数:在函数返回类型前加上static关键字,函数即被定义为静态函

数。静态函数只能在本源文件中使用。

(3)在变量返回类型前加上static关键字,函数即被定义为静态变量。静态变量只

能在本源文件中使用。

(4)定义类的静态成员:在类中,静态成员可以实现多个对象之间的数据共享。静

态成员是类的所有对象中共享的成员,而不是某个对象的成员。对多个对象来说,静态

变量成员只存储一处,供所有对象共用。

(5)定义类的静态函数:静态成员函数和静态成员变量一样,他们都属于类的静态

成员,都不是对象成员,供所有对象共享。因此,对静态成员的引用不需要用对象名,

而是用类名。静态成员函数没有this指针,因此静态成员函数不能访问类中非静态成员

变量。

16、C++四种cast转换(掌握)

(1)const_cast:

将const变量转为非const

(2)static_cast:

最常用,可以用于各种隐式转换,比如非const转const,static_cast可以用于类向上

转换,但向下转换能成功但是不安全。

(3)dynamic_cast:

只能用于含有虚函数的类转换,用于类向上和向下转换。

向上转换:指子类向基类转换。 向下转换:指基类向子类转换。

这两种转换,子类包含父类,当父类转换成子类时可能出现非法内存访问的问题。

dynamic_cast通过判断变量运行时类型和要转换的类型是否相同来判断是否能够进

行向下转换。dynamic_cast可以做类之间上下转换,转换的时候会进行类型检查,类型

相等成功转换,类型不等转换失败。运用RTTI技术,RTTI是”Runtime Type Information”

的缩写,意思是运行时类型信息,它提供了运行时确定对象类型的方法。在c++层面主

要体现在dynamic_cast和typeid,vs中虚函数表的-1位置存放了指向type_info的指针,

对于存在虚函数的类型,dynamic_cast和typeid都会去查询type_info

(4)reinterpret_cast:

reinterpret_cast可以做任何类型的转换,不过不对转换结果保证,容易出问题。

为什么不用C的强制转换:C的强制转换表面上看起来功能强大什么都能转,但是

转换不够明确,不能进行错误检查,容易出错。

17、C++引用和指针的区别(掌握)

(1)指针有自己的一块空间,而引用只是一块别名;

(2)指针大小是4个字节,引用大小是被引用对象的大小;

(3)指针可以被初始化为NULL,而引用必须和一个对象绑定

(4)指针可以指向多个对象,而引用只属于一个对象

(5)有const指针,没有const引用

(6)有二级指针,没有二级引用

18、C++内存泄漏与解决办法(掌握)

(1)通过new、malloc动态申请的堆内存没有及时用delete、free释放

(2)存在继承的父子类,父类析构函数没有定义为虚函数,父类无法调用子类析构

函数释放资源。

(3)Windows的资源,如句柄,位图资源没有及时释放等

解决方法:使用检测工具valgrind;使用智能指针

19、C++智能指针(掌握)

C++里面有四个指针:auto_ptr、unique_ptr、shared_ptr、weak_ptr,后面三个是C++11

支持的,第一个被C++11弃用。

为什么要使用智能指针:智能指针的作用是管理一个指针,因为存在以下这种情况:

申请的空间在函数结束时忘记释放,造成内存泄漏。使用智能指针可以很大程度上避免

这个问题,因为智能指针就是一个类,当超出了类的作用域时,类会自动调用析构函数,

自动释放资源。

auto_ptr:auto指针存在的问题是,两个智能指针同时指向一块内存,就会两次释放

同一块资源,自然报错。

unique_ptr:unique指针规定一个智能指针独占一块内存资源。当两个智能指针同时

指向一块内存,编译报错。

实现原理:将拷贝构造函数和赋值拷贝构造函数申明为private或delete。不允许拷

贝构造函数和赋值操作符,但是支持移动构造函数,通过std:move把一个对象指针变成

右值之后可以移动给另一个unique_ptr

shared_ptr:共享指针可以实现多个智能指针指向相同对象,该对象和其相关资源会

在引用为0时被销毁释放。

实现原理:有一个引用计数的指针类型变量,专门用于引用计数,使用拷贝构造函

数和赋值拷贝构造函数时,引用计数加1,当引用计数为0时,释放资源。

weak_ptr:shared_ptr存在一个问题,当两个shared_ptr指针相互引用时,那么这两

个指针的引用计数不会下降为0,资源得不到释放。因此引入weak_ptr,weak_ptr是弱

引用,weak_ptr的构造和析构不会引起引用计数的增加或减少。

20、什么是野指针(掌握)

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

解决办法:

(1)初始化置NULL

(2)指针释放后置NULL

21、析构函数必须为虚函数吗?构造函数可以为虚函数吗?(掌握)

C++默认虚构函数不是虚函数,因为申明虚函数会创建虚函数表,占用一定内存,当

不存在继承的关系时,析构函数不需要申明为虚函数。若存在继承关系时,析构函数必

须申明为虚函数,这样父类指针指向子类对象,释放基类指针时才会调用子类的析构函

数释放资源,否则内存泄漏。

构造函数不能为虚函数,当申明一个函数为虚函数时,会创建虚函数表,那么这个

函数的调用方式是通过虚函数表来调用。若构造函数为虚函数,说明调用方式是通过虚

函数表调用,但是没构造对象,哪里来的虚函数表?这就成了一个先有鸡还是先有蛋的

问题。

22、构造与析构的顺序(掌握)

构造顺序:基类构造函数》对象成员构造函数》子类构造函数

析构顺序:子类析造函数》对象成员析造函数》基类析造函数

从里向外构造,从外向里析构

23、C++虚函数和多态(掌握)

多态的实现主要分为静态多态和动态多态,静态多态主要是重载,在编译的时候就

已经确定;动态多态是用虚函数机制实现的,在运行期间动态绑定。举个例子:一个父

类类型的指针指向一个子类对象的时候,使用父类的指针去调用子类中重写了的父类中

虚函数的时候,会调用子类重写过后的函数,在父类中声明为加了virtual关键字的函数,

在子类中重写的时候不需要加virtual关键字也是虚函数。

虚函数的实现:在有虚函数的类中,类的最开始部分是一个虚函数表的指针,这个

指针指向一个虚函数表,表中放了虚函数的地址,实际的虚函数在代码段中。当子类继

承了父类的时候也会继承其虚函数表,当子类重写父类中虚函数的时候,会将其继承到

的虚函数表中的地址替换为重新写的函数地址。使用了虚函数,会增加访问内存的开销,

降低效率。

24、new与malloc区别(掌握)

首先,new/delete是C++的关键字,而malloc/free是C语言的库函数,后者使用必

须指明申请内存空间的大小,对于类类型的对象,后者不会调用构造函数和析构函数。

new与malloc区别:

malloc需要给定申请内存的大小,返回的指针需要强转

new会调用构造函数,不用指定内存的大小,返回指针不用强转

25、重载与重写区别(掌握)

重载:两个函数名相同,但是参数列表不同(类型,个数)。返回值类型没有要求,

在同一作用域中。

重写:子类继承了父类,父类中的函数是虚函数,在子类中重新定义了这个虚函数,

这种情况是重写。

26、malloc的实现(掌握)

当开辟的空间小于 128K 时,调用 brk()函数;当开辟的空间大于 128K 时,调

用mmap()。malloc采用的是内存池的管理方式,以减少内存碎片。先申请大块内存

作为堆区,然后将堆区分为多个内存块。当用户申请内存时,直接从堆区分配一块合适

的空闲快。采用隐式链表将所有空闲块,每一个空闲块记录了一个未分配的、连续的内

存地址。

27、volatile、mutable分别怎么用,有什么区别(掌握)

mutable是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可

变的状态,即使在一个const函数中,甚至结构体变量或者类对象为const,其mutable

成员也可以被修改。mutable在类中只能够修饰非静态数据成员。

编译器进行优化时,它有时会取一些值的时候,直接从寄存器里进行存取,而不是

从内存中获取,这种优化在单线程的程序中没有问题,但到了多线程程序中,由于多个

线程是并发运行的,就有可能一个线程把某个公共的变量已经改变了,这时其余线程中

寄存器的值已经过时,但这个线程本身还不知道,以为没有改变,仍从寄存器里获取,

就导致程序运行会出现未定义的行为。并不是因为用volatile修饰了的变量就是“易变”

了,假如没有外因,即使用volatile定义,它也不会变化。而加了volatile修饰的变量,

编译器将不对其相关代码执行优化,而是生成对应代码直接存取原始内存地址

28、C++三种继承方式(掌握)

public: 公有继承时,对基类的公有成员和保护成员的访问属性不变,派生类的新增

成员可以访问基类的公有成员和保护成员,但是访问不了基类的私有成员。派生类的对

象只能访问派生类的公有成员(包括继承的公有成员),访问不了保护成员和私有成员。

protected: 保护继承中,基类的公有成员和保护成员被派生类继承后变成保护成员,

派生类的新增成员可以访问基类的公有成员和保护成员,但是访问不了基类的私有成员。

派生类的对象不能访问派生类继承基类的公有成员,保护成员和私有成员。

private: 私有继承时,基类的公有成员和保护成员都被派生类继承下来之后变成私有

成员,派生类的新增成员可以访问基类的公有成员和保护成员,但是访问不了基类的私

有成员。派生类的对象不能访问派生类继承基类的公有成员,保护成员和私有成员。

总结: 不管是哪种继承方式,派生类中新增成员可以访问基类的公有成员和保护成

员,无法访问私有成员。而继承方式影响的是派生类继承成员访问属性,而使用友元

(friend)可以访问保护成员和私有成员。

29、拷贝构造函数的参数类型为什么必须是引用(掌握)

如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么

就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,

从而造成无穷递归地调用拷贝构造函数。因此拷贝构造函数的参数必须是一个引用。无

法完成拷贝,而且栈也会满。

30、map和set有什么区别(掌握)

set是一种关联式容器,其特性如下:

set以RBTree作为底层容器

所得元素的只有key没有value,value就是key

不允许出现键值重复

所有的元素都会被自动排序

不能通过迭代器来改变set的值,因为set的值就是键,set的迭代器是const的

map和set一样是关联式容器,它们的底层容器都是红黑树,区别就在于map的值

不作为键,键和值是分开的。它的特性如下:

map以RBTree作为底层容器

所有元素都是键+值存在

不允许键重复

所有元素是通过键进行自动排序的

map的键是不能修改的,但是其键对应的值是可以修改的

31、STL的allocator(掌握)

new运算分两个阶段:(1)配置内存;(2)调用构造函数构造对象

delete运算分两个阶段:(1)调用析构函数析构对象;(2)释放内存

为了精密分工,STL allocator将两个阶段操作区分开来,内存配置由alloc::allocate()

负责,内存释放由alloc::deallocate()负责;对象构造由::construct()负责,对象析构

由::destroy()负责。

同时为了提升内存管理效率,减少内存碎片,STL采用两级配置器,当分配的空间

大小超过128b时,使用一级空间配置器,用malloc函数申请内存,小于128b时,使用

二级空间配置器,采用了内存池技术,通过空闲链表来管理内存。

32、说一说STL的迭代器删除问题(掌握)

这是主要考察迭代器失效的问题。

(1)对于序列容器vector,deque来说,使用erase后,后边的每个元素的迭代器

都会失效,后边每个元素都往前移动一位,erase返回下一个有效的迭代器。

(2)对于关联容器map,set来说,使用了erase后,当前元素的迭代器失效,但

是其结构是红黑树,删除当前元素,不会影响下一个元素的迭代器,所以在调用erase

之前,记录下一个元素的迭代器即可。

(3)对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下

一个有效的迭代器,因此上面两种方法都可以使用。

33、STL的基本组成(掌握)

STL由六大部分组成

容器、迭代器、仿函数、算法、分配器、配接器

分配器给容器分配内存空间,算法通过迭代器获取容器中的内容,仿函数可以协助

算法完成各种操作,配接器用来套接适配仿函数。

34、迭代器与指针的区别(掌握)

迭代器不是指针,是类模板,表现的像指针。只是模拟了指针的一些功能,通过重

载指针的一些操作符,->、*、++、--等。本质封装了原生指针,是指针概念的一种提升,

提供了比指针更高级的行为,相当于一种智能指针。

迭代器的产生就是为了在不用暴露集合内部的结构下而达到遍历集合的效果。

35、左值引用与右值引用的区别(掌握)

左值:既可以放等号左边,又可以放等号右边的值或变量,称为左值。

右值:只能放等号右边的值或变量,称为右值。

左值引用与右值引用的区别:

(1)左值可以寻址,而右值不可以

(2)左值可以被赋值,右值不可以被赋值,可以用来给左值赋值

(3)左值可变,右值不可以

操作系统

1、操作系统的用户态和内核态(掌握)

内核态与用户态是操作系统的两种运行级别。内核态拥有最高权限,可以访问所有

系统指令;用户态则只能访问一部分指令。

为什么区分内核态与用户态:在CPU的所有指令中,有一些指令是非常危险的,如

果错用,将导致整个系统崩溃。比如:清内存、设置时钟等。

两者如何切换:(1)发生系统调用时。这是处于用户态的进程主动请求切换到内核

态的一种方式;(2)产生异常时,如缺页异常;(3)外设产生中断时。

系统调用是进程主动请求发生切换的,中断和异常都是被动的。

2、操作系统的功能有哪些(掌握)

操作系统(Operating System,简称OS)是一管理电脑硬件与软件资源的程序,同

时也是计算机系统的内核与基石。操作系统是一个庞大的管理控制程序,大致包括5个

方面的管理功能:进程与处理机管理、作业管理、存储管理、设备管理、文件管理

进程管理:主要是对处理机进行管理。

存储管理:主要是对内存的分配、保护和扩充。

设备管理:对所有输人、输出设备的管理。

文件管理:主要涉及文件的逻辑组织和物理组织,目录的结构和管理。

作业管理:为用户提供一个友好的环境,方便用户组织自己的工作流程。

3、proc下面有什么文件,都是干嘛的(掌握)

/proc/cmdline文件:这个文件给出了内核启动的命令行。它和用于进程的cmdline

项非常相似。

/proc/cpuinfo文件:这个文件提供了有关系统CPU的多种信息。这些信息是从内核

里对CPU的测试代码中得到的。

/proc/devices文件:这个文件列出字符和块设备的主设备号,以及分配到这些设备

号的设备名称。

/proc/dma文件:这个文件列出由驱动程序保留的DMA通道和保留它们的驱动程序

名称。

/proc/interrupts文件:这个文件的每一行都有一个保留的中断。

/proc/ioports文件:这个文件列出了诸如磁盘驱动器,以太网卡和声卡设备等多种设

备驱动程序登记的许多I/O端口范围。

/proc/kcore文件:这个文件是系统的物理内存以core文件格式保存的文件。

4、并行与并发的区别(掌握)

并发和并行的区别很明显。它们虽然都说是"多个进程同时运行",但是它们的"同时

"不是一个概念。并行的"同时"是同一时刻可以多个进程在运行(处于running),并发的"

同时"是经过上下文快速切换,使得看上去多个进程同时都在运行的现象,是一种OS欺

骗用户的现象。

5、线程与进程的区别(掌握)

进程:进程是对程序运行时的封装,是系统资源调度的最小单位,对于单核CPU来

说,实现了操作系统的并发;多核CPU可实现并行。

线程:线程是进程的子任务,是CPU调度的最小单位,实现了进程内部的并发。

区别:

(1)一个线程从属于一个进程;一个进程可以包含多个线程。

(2)一个线程挂掉,对应的进程挂掉;一个进程挂掉,不会影响其他进程。

(3)进程是系统资源调度的最小单位;线程CPU调度的最小单位。

(4)进程系统开销显著大于线程开销;线程需要的系统资源更少。

(5)进程在执行时拥有独立的内存单元,多个线程共享进程的内存,如代码段、数

据段、扩展段;但每个线程拥有自己的栈段和寄存器组。

(6)进程切换时需要刷新TLB并获取新的地址空间,然后切换硬件上下文和内核

栈,线程切换时只需要切换硬件上下文和内核栈。

(7)通信方式不一样。

(8)进程适应于多核、多机分布;线程适用于多核

6、线程与进程的通信方式(掌握)

进程:进程间通信主要包括管道、系统IPC(包括消息队列、信号量、信号、共享

内存)、套接字socket。

(1)管道:包括无名管道和命名管道,无名管道半双工,只能用于具有亲缘关系的

进程直接的通信(父子进程或者兄弟进程),可以看作一种特殊的文件;命名管道可以

允许无亲缘关系进程间的通信。

(2)系统IPC

消息队列:消息的链接表,放在内核中。消息队列独立于发送与接收进程,进

程终止时,消息队列及其内容并不会被删除;消息队列可以实现消息的随机查询,

消息不一定要以先进先出的次序读取,也可以按照消息的类型读取。

信号量semaphore:是一个计数器,可以用来控制多个进程对共享资源的访问。

信号量用于实现进程间的互斥与同步。

信号:用于通知接收进程某个事件的发生。

内存共享:使多个进程访问同一块内存空间。

(3)套接字socket:用于不同主机直接的通信。

线程:线程间的通信方式包括临界区、互斥量、信号量、信号:

(1)临界区:每个线程中访问临界资源的那段代码称为临界区(Critical Section)

(临界资源是一次仅允许一个线程使用的共享资源)。每次只准许一个线程进入临界区,

进入后不允许其他线程进入。不论是硬件临界资源,还是软件临界资源,多个线程必须

互斥地对它进行访问。

(2)互斥量:采用互斥对象机制,只有拥有互斥对象的线程才可以访问。因为互斥

对象只有一个,所以可以保证公共资源不会被多个线程同时访问。

(3)信号量:计数器,允许多个线程同时访问同一个资源。

(4)信号:通过通知操作的方式来保持多线程同步。

7、线程间的同步方式及具体的调用(掌握)

(1)信号量:信号量是一种变量,可用于线程同步。去自然数值。支持两种操作。

P(SV):如果信号量SV大于0,将它减一;如果SV为0,则挂起该线程

V(SV):如果有其他线程因为等等SV而挂起,则唤醒,将SV+1,否则直接

SV+1。

系统调用为:

sem_wait(sem_t *sem):以原子操作的方式将信号量减1,如果信号量值为0,

则sem_wait将被阻塞,知道这个信号量具有非0值。

sem_post(sem_t *sem):以原子操作的方式将信号量加1,当信号量大于0时,

其他正在调用sem_wait等待信号量的线程将被唤醒。

(2)互斥量:互斥量又称互斥锁,用于线程互斥,不能保证按序访问,进入临界区

时,线程加锁,出临界区时,解锁。

pthread_mutex_t:定义一个互斥锁

pthread_mutex_init:初始化互斥锁

pthread_mutex_destroy:销毁互斥锁

pthread_mutex_lock:加锁

pthread_mutex_unlock:解锁

(3)条件变量:条件变量是线程中的东西,就是等待某一条件的发生,和信号一样。

pthread_cond_init:初始化条件变量

pthread_cond_destroy:销毁条件变量

pthread_cond_signal:通知一个线程

pthread_cond_broadcast:通知所有线程

pthread_cond_wait:等待条件触发

8、线程与协程(掌握)

协程:微线程,在子程序内部执行,可在子程序内部中断,转而执行别的子程序,

在适当的时候再返回来接着执行。

区别:

(1)协程执行效率极高。因为子程序切换不是线程切换,而是由程序自身控制,因

此,没有线程切换的开销。

(2)协程不需要多线程的锁机制,因为多个协程从属于一个线程,不存在同时写变

量冲突,在协程切换不需要加锁,执行判断状态,因此效率比线程高。

9、常用线程模型(了解)

(1)Future模型:该模型通常配合Callable接口使用。Future是把结果放在将来获

取,当前主线程并不急于处理结果。允许子线程先处理一段时间,处理结果保持下来,

当主线程需要的时候再从子线程获取。

(2)Fork&join模型:包含递归和回溯思想,递归拆分任务,回溯合并结果。将大

任务拆分成小任务分别在子线程中执行,子线程执行完毕后逐级回溯,合并结果。

(3)Actor模型:基于消息机制并行任务处理。以消息的形式进行线程间数据传输。

(4)生产者消费者模型:使用一个队列保存任务,开启一个线程池,有任务到来,

挂到队列,再通过条件变量通知线程处理。队列为空时,线程阻塞。

(5)Master-worker模型:一个master主线程接收任务,再分发给worker子线程。

worker子线程将处理完的结果返回给master主线程。

10、操作系统中的内存结构(掌握)

从低地址到高地址,一个程序由代码段、数据段、BSS段组成。

代码段:存放程序执行代码的一块内存区域。只读,代码段的头部还会包含一些只

读的常数变量。

数据段:存放程序中已初始化的全局变量和静态变量的一块内存区域。

BSS段:存放程序中未初始化的全局变量和静态变量的一块内存区域。

可执行程序在运行时又会多出两个区域:堆区和栈区。

堆区:动态申请内存用。堆从低地址向高地址增长。

栈区:存储局部变量、函数参数值。栈从高地址向低地址增长。是一块连续的空间。

最后还有一个文件映射区,位于堆和栈之间。

11、linux虚拟内存(掌握)

虚拟内存是一种内存管理技术。

虚拟内存技术使得不同的进程在运行过程中,它所看到的是自己独占的4G内存空

间。所有进程共享同一物理内存,每个进程只把自己的虚拟内存空间映射并存储到物理

内存上。

虚拟内存的好处:

(1)扩大地址空间。每个进程独占一个4G空间,虽然真实物理内存没那么多。

(2)内存保护:防止不同进程对物理内存的争夺和践踏,可以对特定内存地址提供

写保护,防止恶意篡改。

(3)可以实现内存共享,方便进程通信。

(4)可以避免内存碎片,虽然物理内存可能不连续,但映射到虚拟内存上可以连续。

虚拟内存的代价:

(1)虚拟内存需要额外构建数据结构,占用空间。

(2)虚拟地址到物理地址的转换,增加了执行时间。

(3)页面换入换出耗时。

(4)一页如果只有一部分数据,浪费内存。

12、操作系统的页表寻址(掌握)

页式内存管理,内存分成固定长度的一个个页片。操作系统为每一个进程维护了一

个从虚拟地址到物理地址的映射关系的数据结构,叫页表。页表的内容就是该进程的虚

拟地址到物理地址的一个映射。页表中的每一项都记录了这个页的基地址。

三级页表转换方法:

(1)逻辑地址转线性地址:段起始地址+段内偏移地址=线性地址

(2)线性地址转物理地址:

每一个32位的线性地址被划分为三部分:页目录索引(10位)、页表索引(10

位)、页内偏移(12位)

从cr3中取出进程的页目录地址(操作系统调用进程时,这个地址被装入寄存

器中)

页目录地址 + 页目录索引 = 页表地址

页表地址 + 页表索引 = 页地址

页地址 + 页内偏移 = 物理地址

13、操作系统的缺页中断(掌握)

缺页异常:malloc和mmap函数在分配内存时只是建立了进程虚拟地址空间,并没

有分配虚拟内存对应的物理内存。当进程访问这些没有建立映射关系的虚拟内存时,处

理器自动触发一个缺页异常。

缺页中断:缺页异常后将产生一个缺页中断,此时操作系统会根据页表中的外存地

址在外存中找到所缺的一页,将其调入内存。

缺页中断与一般中断一样,需要经历四个步骤:保护CPU现场、分析中断原因、转

入缺页中断处理程序、恢复CPU现场,继续执行。

缺页中断与一般中断区别:

(1)在指令执行期间产生和处理缺页中断信号

(2)一条指令在执行期间,可能产生多次缺页中断

(3)缺页中断返回的是执行产生中断的一条指令,而一般中断返回的是执行下一条

指令。

14、缺页置换算法(掌握)

当访问一个内存中不存在的页,并且内存已满,则需要从内存中调出一个页或将数

据送至磁盘对换区,替换一个页,这叫缺页置换。

先进先出(FIFO)算法:队列,删除队首的页即可

LRU算法:置换最近一段时间以来最长时间未访问的页面。

LFU算法:置换最近一段时间以来访问频率最低的页面。

15、fork(掌握)

pid_t fork(void)

成功调用fork()会创建一个一模一样新的进程,这两个进程都会继续运行。在子进程

中,成功的fork()调用会返回0。在父进程中fork()返回子进程的pid。如果出现错误,fork()

返回一个负值。

早期fork()创建子进程,会将父进程的内存空间复制一份。后来采用写时复制的做法,

即父子进程共享内存空间,当子进程修改资源时,再复制内存空间。

16、死锁发生条件已经如何解决死锁(掌握)

死锁是指两个或两个以上进程在执行过程中,因争夺资源而造成的相互等待的现象。

死锁发生有四个必要条件:

(1)互斥条件:进程对所分配到的资源不允许其他进程访问,若其他进程访问,只

能等待,直到占有该资源的进程使用完成后释放该资源;

(2)请求保持条件:进程获得一定资源后,又对其他资源发出请求,但该资源被其

他进程占有,此时请求阻塞,但该进程不会释放自己已经占有的资源;

(3)不可剥夺条件:进程已获得的资源,只能自己释放,不可剥夺;

(4)环路等待条件

解决办法:

(1)资源一次性分配,从而解决请求保持的问题

(2)可剥夺资源:当进程新的资源未得到满足时,释放已有的资源;

(3)资源有序分配:资源按序号递增,进程请求按递增请求,释放则相反。

17、锁的类型(掌握)

互斥锁:mutex,保证在任何时刻,都只有一个线程访问该资源,当获取锁操作失败

时,线程进入睡眠,等待锁释放时被唤醒。

读写锁:rwlock,分为读锁和写锁,处于读操作时,可以运行多个线程同时读。但

写时同一时刻只能有一个线程获得写锁。

互斥锁和读写锁的区别:

(1)读写锁区分读锁和写锁,而互斥锁不区分

(2)互斥锁同一时间只允许一个线程访问,无论读写;读写锁同一时间只允许一个

线程写,但可以多个线程同时读。

自旋锁:spinlock,在任何时刻只能有一个线程访问资源。但获取锁操作失败时,不

会进入睡眠,而是原地自旋,直到锁被释放。这样节省了线程从睡眠到被唤醒的时间消

耗,提高效率。

条件锁:就是所谓的条件变量,某一个线程因为某个条件未满足时可以使用条件变

量使该程序处于阻塞状态。一旦条件满足了,即可唤醒该线程(常和互斥锁配合使用)

18、进程的状态转换(掌握)

(1)创建:进程正在被创建

(2)就绪:等待CPU调度运行

(3)执行:

(4)等待阻塞:

(5)终止:

为什么需要就绪状态:

当多个进程竞争内存资源时,会造成内存资源紧张,并且,如果没有就绪状态,处

理机会空闲,IO速度比处理机速度慢得多,可能出现全部进程阻塞等待IO

针对以上问题,提出交换技术,交换技术是换出一部分进程到外存,腾出内存空间。

在交换技术上,将内存暂时不能运行的进程,或者暂时不用的数据和程序,换出到外存,

来腾出足够的内存空间,把已经具备运行条件的进程,或进程所需的数据和程序换入到

内存。从而出现了进程的挂起状态(等待阻塞),进程被交换到外存,进程状态就成为

了挂起状态。

19、软链接和硬链接的区别(掌握)

硬链接就是同一个文件使用了不同的别名,使用ln创建。

若文件用户数据块中存放的内容是另一个文件的路径名指向,则该文件是软链接。

软链接是一个普通文件,有自己独立的inode。

20、如何判断大端和小端(掌握)

小端模式:低的有效字节存储在低的存储器地址。

大端模式:高的有效字节存储在低的存储器地址。

我们可以根据联合体来判断系统是大端还是小端。因为联合体变量总是从低地址存

int fun1(){

union test{

int i;

char c;

};

test t; t.i = 1;

//如果是大端,则t.c为0x00,则t.c != 1,反之是小端

return (t.c == 1);

}

21、内存溢出和内存泄漏(掌握)

(1)内存溢出:程序申请内存时,没有足够的内存供申请者使用。

原因:内存中加载的数据量过于庞大;代码中死循环,栈溢出等

(2)内存泄漏:程序申请内存后未及时释放。

分类:

堆内存泄漏:使用new或malloc申请内存后,没有及时使用delete和free释放内存。

子类继承父类时,父类析构函数没有设置为虚函数,那么父类调用子类对象后就没

办法及时调用子类的析构函数释放资源,造成内存泄漏。

系统资源泄漏:比如Windows的句柄、位图等资源使用后未及时释放。

22、系统调用是什么?(掌握)

系统调用又称系统呼叫,指运行在使用者空间的程序向操作系统内核请求需要更高

权限运行的服务。

内核态与用户态是操作系统的两种运行级别。内核态拥有最高权限,可以访问所有

系统指令;用户态则只能访问一部分指令。

为什么区分内核态与用户态:在CPU的所有指令中,有一些指令是非常危险的,如

果错用,将导致整个系统崩溃。比如:清内存、设置时钟等。

但是有些指令又需要给用户态权限,于是有了系统调用,危险的指令被包装成系统

调用,用户通过系统调用运行那些危险的指令。

当向一个文件里写入内容时,open和write都是系统调用。

23、用户空间与内核通信方式有哪些?(掌握)

(1)直接使用API:get_user()put_user()

(2)使用proc文件系统

(3)使用mmap系统调用

(4)信号

24、什么是僵尸进程?(掌握)

(1)正常进程

正常情况下,子进程是通过父进程创建的,子进程再创建新的进程。当一个进程完

成它的工作终止后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止

状态并释放子进程。

(2)孤儿进程

一个父进程退出,而它的一个或多个子进程还在运行,那么这些进程将成为孤儿进

程。孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。

(3)僵尸进程

一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid

获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为

僵尸进程。这是每个子进程在结束时都要经过的阶段。但如果进程不调用wait()或者

waitpid()的话,那么子进程的进程描述符仍然保存在系统中不被释放,占用系统资源。

解决僵尸进程方法如下:1)父进程通过wait或waitpid函数等待子进程结束。

2)如果父进程很忙,可以采用异步的方式,注册SIGCHLD信号处理函数,在处理

函数中wait回收子进程。

3)还可以比如fork两次。子进程退出,孙进程就由init进程接管回收了。

25、什么是守护进程?如何创建?(掌握)

守护进程:守护进程是运行在后台的一种生存期长的特殊进程。它独立于控制终端,

处理一些系统级别任务。

创建过程:

(1)让程序在后台执行。方法是调用fork()产生一个子进程,然后使父进程退出。

(2)调用setsid()创建一个新对话期。控制终端、登录会话和进程组通常是从父

进程继承下来的,守护进程要摆脱它们,不受它们的影响,方法是调用setsid()使进程

成为一个会话组长。setsid()调用成功后,进程成为新的会话组长和进程组长,并与原

来的登录会话、进程组和控制终端脱离。

(3)禁止进程重新打开控制终端。经过以上步骤,进程已经成为一个无终端的会话

组长,但是它可以重新申请打开一个终端。为了避免这种情况发生,可以通过使进程不

再是会话组长来实现

(4)关闭不再需要的文件描述符。子进程从父进程继承打开的文件描述符。如不关

闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。

(5)将当前目录更改为根目录。

26、操作系统中的进程调度策略有哪几种?(掌握)

(1)先来先服务调度算法

(2)短作业(进程)优先调度算法

(3)高优先级优先调度算法

(4)时间片轮转法

(5)多级反馈队列调度算法

27、抢占式与非抢占式的区别?(掌握)

(1)非抢占式优先权算法

在这种方式下,系统一旦把处理机分配给就绪队列中优先权最高的进程后,该进程

便一直执行下去,直至完成;或因发生某事件使该进程放弃处理机时,系统方可再将处

理机重新分配给另一优先权最高的进程。这种调度算法主要用于批处理系统中;也可用

于某些对实时性要求不严的实时系统中。

(2)抢占式优先权调度算法

在这种方式下,系统同样是把处理机分配给优先权最高的进程,使之执行。但在其

执行期间,只要又出现了另一个其优先权更高的进程,进程调度程序就立即停止当前进

程(原优先权最高的进程)的执行,重新将处理机分配给新到的优先权最高的进程。因此,

在采用这种调度算法时,是每当系统中出现一个新的就绪进程i 时,就将其优先权Pi与

正在执行的进程j 的优先权Pj进行比较。如果Pi≤Pj,原进程Pj便继续执行;但如果

是Pi>Pj,则立即停止Pj的执行,做进程切换,使i 进程投入执行。显然,这种抢占式

的优先权调度算法能更好地满足紧迫作业的要求,故而常用于要求比较严格的实时系统

中,以及对性能要求较高的批处理和分时系统中。

非抢占式(Nonpreemptive):让进程运行直到结束或阻塞的调度方式,容易实现,

适合专用系统,不适合通用系统。

抢占式(Preemptive):允许将逻辑上可继续运行的在运行过程暂停的调度方式可防

止单一进程长时间独占,CPU系统开销大(降低途径:硬件实现进程切换,或扩充主存

以贮存大部分程序)

28、IO模型有哪几种?(掌握)

(1)阻塞IO:调用者调用了某个函数,等待这个函数返回,期间什么也不做,不

停的检查这个函数有没有返回,必须等这个函数返回后才能进行下一步动作。

(2)非阻塞IO:非阻塞等待,每隔一段时间就去检查IO事件是否就绪。没有就绪

就可以做其他事情。

(3)信号驱动IO:Linux用套接口进行信号驱动IO,安装一个信号处理函数,进

程继续运行并不阻塞,当IO事件就绪,进程收到SIGIO信号,然后处理IO事件。

(4)IO多路复用:Linux用select/poll函数实现IO复用模型,这两个函数也会使

进程阻塞,但是和阻塞IO所不同的是这两个函数可以同时阻塞多个IO操作。而且可以

同时对多个读操作、写操作的IO函数进行检查。知道有数据可读或可写时,才真正调用

IO操作函数。

(5)异步IO:Linux中,可以调用aio_read函数告诉内核描述字缓冲区指针和缓冲

区的大小、文件偏移及通知的方式,然后立即返回,当内核将数据拷贝到缓冲区后,再

通知应用程序。用户可以直接去使用数据。异步和同步的区别就在于,异步是内核将数

据拷贝到用户区,不需要用户再自己接收数据,直接使用就可以了,而同步是内核通知

用户数据到了,然后用户自己调用相应函数去接收数据。

29、怎么实现线程池?(掌握)

实现线程池:

(1) 设置一个生产者消费者队列,作为临界资源。

(2) 初始化n个线程,并让其运行起来,加锁去队列里取任务运行

(3) 当任务队列为空时,所有线程阻塞。

(4) 当生产者队列来了一个任务后,先对队列加锁,把任务挂到队列上,然后使

用条件变量去通知阻塞中的一个线程来处理。

为什么要创建线程池:

创建线程和销毁线程的花销是比较大的,这些时间有可能比处理业务的时间还要长。

这样频繁的创建线程和销毁线程,再加上业务工作线程,消耗系统资源的时间,可能导

致系统资源不足。

线程池如何确定线程数量:

线程和哪些因素有关:CPU,IO、并行、并发

如果是CPU密集型应用,则线程池大小设置为CPU数目+1

如果是IO密集型应用,则线程池大小设置为2*CPU数目+1

最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目

所以线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需

要越少线程

线程池的核心线程与普通线程:

任务队列可以存放100个任务,此时为空,线程池里有10个核心线程,若突然来了

10个任务,那么刚好10个核心线程直接处理;若又来了90个任务,此时核心线程来不

及处理,那么有80个任务先入队列,再创建核心线程处理任务;若又来了120个任务,

此时任务队列已满,不得已,就得创建20个普通线程来处理多余的任务。

以上是线程池的工作流程。

30、Linux下如何调试程序?(掌握)

GDB调试:gdb调试的是可执行文件,在gcc编译时加入 -g ,告诉gcc在编译时

加入调试信息,这样gdb才能

调试这个被编译的文件 gcc -g tesst.c -o test

GDB命令格式:

gdb -q test 启动时不输出版权说明

quit 退出gdb,结束调试

list: 查看程序源代码,显示10行

list 5,10: 显示5到10行的代码

list test.c:5, 10:显示源文件5到10行的代码,在调试多个文件时使用

list get_sum: 显示get_sum函数周围的代码

list test,c get_sum: 显示源文件get_sum函数周围的代码,在调试多个文件时使用

reverse-search 字符串 用来从当前行向前查找第一个匹配的字符串

run 程序开始执行

help list/all 查看帮助信息

break 设置断点

break 7 在第七行设置断点

break get_sum 以函数名设置断点

break 行号或者函数名 if 条件 以条件表达式设置断点

watch 条件表达式 条件表达式发生改变时程序就会停下来

awatch 和watch类似,在表达式值发生改变或者表达式值被读取时,暂停

next 继续执行下一条语句 ,会把函数当作一条语句执行

step 继续执行下一条语句,会跟踪进入函数,一次一条的执行函数内的代码

nexti 单步执行一条机器指令 通常一条语句由多条机器指令构成,不进函数

stepi 单步执行一条机器指令, 跟踪进入函数

31、Linux常用命令行?(掌握)

(1) cd命令:用于切换当前目录

(2) ls命令:查看当前文件与目录

(3)grep命令:该命令常用于分析一行的信息,若当中有我们所需要的信息,就将

该行显示出来,该命令通常与管道命令一起使用,用于对一些命令的输出进行筛选加工。

(4)cp命令:复制命令

(5)mv命令:移动文件或文件夹命令

(6)rm命令:删除文件或文件夹命令

(7)ps命令:查看进程情况

(8)kill命令:向进程发送终止信号

(9)tar命令:对文件进行打包,调用gzip或bzip对文件进行压缩或解压

(10)cat命令:查看文件内容,与less、more功能相似

(11)top命令:可以查看操作系统的信息,如进程、CPU占用率、内存信息等

(12)pwd命令:命令用于显示工作目录。

32、负载均衡?(掌握)

当一台服务器的单位时间内的访问量越大时,服务器压力就越大,大到超过自身承

受能力时,服务器就会崩溃。为了避免服务器崩溃,让用户有更好的体验,我们通过负

载均衡的方式来分担服务器压力。

我们可以建立很多很多服务器,组成一个服务器集群,当用户访问网站时,先访问

一个中间服务器,在让这个中间服务器在服务器集群中选择一个压力较小的服务器,然

后将该访问请求引入该服务器。如此以来,用户的每次访问,都会保证服务器集群中的

每个服务器压力趋于平衡,分担了服务器压力,避免了服务器崩溃的情况。

负载均衡是用反向代理的原理实现的。

(1)轮询(默认)

请求依次轮流往每个应用服务器上进行分配,分配策略比较简单。

缺点:不均匀,可能会出现,某些服务器接受的请求较重,负载压力重,有些负荷

小,不可控。另外服务器之间需要进行session同步。

(2)权重轮询(权重越高,进入的几率越大)

优点:可以根据情况进行调整。可控,仍然需要进行session同步。

(3)IP-Hash

优点:无需进行session同步,固定IP会固定访问一台服务器。

缺点:恶意攻击,会造成某台服务器压垮。提供的服务不同,面向的地区不同,IP

可能会出现集中,造成不均匀,不可控。

(4)Fair

这种相当于自适应,会根据服务器处理请求的速度进行负载均衡分配。处理请求最

早结束的,拿到下一个请求。看上去是不是很好。但是一般都不使用,说是考虑到网络

不稳定因素。还有待研究。这种也需要进行session同步。

(5)URL-Hash

这种是根据URL进行hash,这样某些请求永远打某台服务器。利于利用服务器的缓

存,但是可能由于URL的哈希值分布不均匀,以及业务侧重造成某些服务器压力大,某

些负荷低。这种也需要进行session同步。

33、公平锁与非公平锁(掌握)

公平锁:就是很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等

待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就会加入到等

待队列中,以后会按照FIFO的规则从队列中取到自己

非公平锁:非公平锁比较粗鲁,上来就直接尝试占有锁,如果尝试失败,就再采用

类似公平锁那种方式。

非公平锁的优点在于吞吐量比公平锁大。

34、死锁与活锁(掌握)

死锁:是指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的

一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状

态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

活锁:是指线程1可以使用资源,但它很礼貌,让其他线程先使用资源,线程2也

可以使用资源,但它很绅士,也让其他线程先使用资源。这样你让我,我让你,最后两

个线程都无法使用资源。

35、乐观锁与悲观锁(掌握)

悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次

在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系

型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做

操作之前先上锁。

乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以

不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使

用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供

的类似于write_condition机制,其实都是提供的乐观锁。

要明确一下:无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一

种思想。其实不仅仅是关系型数据库系统中有乐观锁和悲观锁的概念,像memcache、

hibernate、tair等都有类似的概念。所以,不应该拿乐观锁、悲观锁和其他的数据库锁等

进行对比。

实现方式:

悲观锁的实现可以依靠数据库里的锁机制,如排它锁。

乐观锁的实现Compare and Swap(CAS):当多个线程尝试使用CAS同时更新同一个

变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被

挂起,而是被告知这次竞争中失败,并可以再次尝试。

乐观锁每次在执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据的

版本号一致就可以执行修改操作并对版本号执行+1操作,否则就执行失败。因为每次操

作的版本号都会随之增加,所以不会出现ABA问题,因为版本号只会增加不会减少。

除了version以外,还可以使用时间戳,因为时间戳天然具有顺序递增性。

计算机网络

1、当你在浏览器地址栏输入一个URL后回车,将会发生的事情?(掌握)

(1)客户端、服务端层面来看:

域名解析 --> 发起TCP的3次握手 --> 建立TCP连接后发起http请求 --> 服务器

响应http请求,浏览器得到html代码 --> 浏览器解析html代码,并请求html代码中的

资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户。

域名解析:浏览器会首先搜索浏览器的DNS缓存;如果浏览器自身的缓存里面没有

找到对应的条目,那么浏览器会搜索操作系统的DNS缓存;如果在Windows系统的DNS

缓存也没有找到,那么尝试读取hosts文件;如果在hosts文件中也没有找到对应的条目,

浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器(本地名称

服务器)发起域名解析请求,有两种方式,一种递归,一种迭代。

发起TCP的3次握手建立TCP连接。

建立TCP连接后发起http请求:HTTP请求报文的方法是get方式或post方式

服务器响应http请求,浏览器得到html代码

浏览器解析html代码,并请求html代码中的资源

浏览器对页面进行渲染呈现给用户

总的来说,CPU从内存中一条一条地取出指令和相应的数据,按指令操作码的规定,对数据

(2)TCP五层网络模型来看:

应用层:浏览器要将url解析为IP地址,解析域名就要用到DNS协议,首先主机会

查询DNS的缓存,如果没有就给本地DNS发送查询请求。查询有两种,一种是递归查

询,一种是迭代查询。DNS服务器是基于UDP的,因此也会用到UDP协议。

得到IP地址后,浏览器就要与服务器建立一个http连接。因此用到http协议,TCP

三次握手后,http发送get或post请求。

传输层:TCP层将http数据包分片打包,然后TCP的数据会发送给IP层。

网络层:IP协议。IP层通过路由选路,一边中转,一边传输数据。

数据链路层:当发送数据时,数据链路层的任务是将在网络层交下来的IP数据组装

成帧,控制信息使接收端能够知道一个帧从哪个比特开始和到哪个比特结束。

物理层:传输电信号。

2、说一下TCP怎么保证可靠性,并简述一下TCP建立连接和断开连接的过程(掌握)

TCP保证可靠性:

(1)序列号、确认应答、超时重传

数据到达接收方,接收方需要发出一个确认应答,表示已经收到该数据段,并且确

认序列号,序列号说明了它下一次需要接收的数据序列号,保证数据传输有序。如果发

送方迟迟未收到确认应答,那么可能是发送的数据丢失,也可能是确认应答丢失,这时

发送方在等待一段时间后进行重传

(2)窗口控制

TCP会利用窗口控制来提高传输速度,意思是在一个窗口大小内,不用一定等到应

答才能发送下一段数据,窗口大小就是无需等待确认而可以继续发送数据的最大值。如

果不使用窗口控制,每一个没收到确认应答的数据都要重发。

使用窗口控制,如果数据段1001-2000丢失,后面数据每次传输,确认应答都会不

停发送序号为1001的应答,表示我要接收1001开始的数据,发送端如果收到3次相同

应答,就会立刻进行重发;数据一旦丢失,接收端会一直提醒。

(3)拥塞控制

如果把窗口定的很大,发送端连续发送大量的数据,可能造成网络的拥堵。为了防

止拥堵,进行拥塞控制

慢启动:定义拥塞窗口,一开始将该窗口大小设为1,之后每次收到一次确认应答,

将拥塞窗口大小*2

拥塞避免:设置慢启动阈值,一般开始都设为65536。拥塞避免是只当拥塞窗口大

小达到这个阈值,拥塞窗口的值不再指数上升,而是+1

快恢复:将报文段的超时重传看做拥塞,则一旦发生超时重传,我们就将阈值设为

当前窗口大小的一半,并且窗口大小变为1,重新进入慢启动过程

快速重传:3次重复确认应答,立即重传。

三次握手:

(1)Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给

Server,Client进入SYN_SENT状态,等待Server确认。

(2)Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标

志位SYN和ACK都置1,ack=J+1,随机产生一个值seq=K,并将该数据包发给Client

以确认连接请求,Server进入SYN_RCVD状态。

(3)Client收到确认后,检测ack是否为J+1,ACK是否为1,如果正确则将标志

位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检测ack是否为K+1,

ACK是否为1,如果正确则连接成功,Client和Server进入ESTABLISHED状态,完成

三次握手,随后Client与Server之间可以开始传输数据了。

四次挥手:

(1)数据传输结束后,客户端的应用进程发出连接释放报文段,并停止发送数据,

客户端进入FIN_WAIT_1状态,此时客户端依然可以接收服务器发送来的数据。

(2)服务器接收到FIN后,发送一个ACK给客户端,确认序号为收到的序号+1,

服务器进入CLOSE_WAIT状态。客户端收到后进入FIN_WAIT_2状态。

(3)当服务器没有数据要发送时,服务器发送一个FIN报文,此时服务器进入

LAST_ACK状态,等待客户端的确认。

(4)客户端收到服务器的FIN报文后,给服务器发送一个ACK报文,确认序列号

为收到的序号+1.此时客户端进入TIME_WAIT状态,等待2MSL(MSL:报文段最大生

存时间),然后关闭连接。

3、为什么要三次握手(掌握)

假如只进行两次握手,客户端发送连接请求后,会等待服务器端的应答。但是会出

现的问题是,假如客户端的SYN迟迟没有到达服务器端,此时客户端超时后,会重新发

送一次连接,假如重发的这次服务器端收到了,且应答客户端了,连接建立了。但是建

立后,第一个SYN也到达服务端了,这时服务端会认为这是一个新连接,会再给客户端

发送一个ACK,这个ACK当然会被客户端丢弃。但是此时服务器端已经为这个连接分

配资源了,而且服务器端会一直维持着这个资源,会造成浪费

三次握手,两次握手的问题在于服务器端不知道SYN的有效性,所以如果是三次握

手,服务器端会等待客户端的第三次握手,如果第三次握手迟迟不来,服务器端就会释

放相关资源。

4、http和https的区别(掌握)

(1)http是是明文传输,https则是具有安全性的tsl加密传输协议。

(2)https除了三次握手以外,还要进行ssl握手,协商加密使用对称密钥

(3)https需要服务端申请证书,浏览器端安装根证书

(4)端口也不一样,前者是80,后者是443

5、http返回码(掌握)

301 Permanently Moved 被请求的资源已永久移动到新位置,新的URL在Location

头中给出,浏览器应该自动地访问新的URL。

302 Found 请求的资源现在临时从不同的URL响应请求。

301是永久重定向,而302是临时重定向。

200 OK,表示从客户端发来的请求在服务器端被正确处理

304 Not Modified:304状态码是告诉浏览器可以从缓存中获取所请求的资源。

400 bad request,请求报文存在语法错误

403 forbidden,表示对请求资源的访问被服务器拒绝

404 not found,表示在服务器上没有找到请求的资源

500 internal sever error,表示服务器端在执行请求时发生了错误

503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求

6、IP地址和MAC地址(掌握)

IP地址是IP协议提供的一种统一的地址格式,为互联网上的每一个网络和每一台主

机分配一个逻辑地址,一次来屏蔽物理地址的差异。同一个局域网内IP地址不相同,不

同的局域网IP地址可以相同。

MAC地址一个硬件地址,用来定义网络设备的位置。

7、OSI七层模型和TCP/IP四层模型,每层列举2个协议(掌握)

OSI七层模型:

物理层:IEE802.3、CLOCK、RJ45

数据链路层:MAC、VLAN、PPP

网络层:IP、ARP、ICMP

传输层:TCP、UDP

会话层:RPC、NFS

表示层:JPEG、ASII

应用层:FTP、HTTP、DNS

TCP/IP四层模型:

数据链路层:MAC、VLAN

网络层:IP、ARP、ICMP

传输层:TCP、UDP

应用层:HTTP、DNS

物理层

8、TCP与UDP的区别(掌握)

区别:

(1)TCP需要建立一对一稳定连接,UDP无连接

(2)TCP一对一,UDP可以一对一、一对多、多对多

(3)TCP可靠传输,序列号、确认应答、超时重传;UDP不保证可靠传输

(4)TCP头部字节20字节,UDP8个字节

(5)TCP开销大,UDP灵活开销小

(6)TCP用于重要信息的传输,UDP可以用于视频、语音传输

9、TCP和UDP协议的头部数据(掌握)

10、Time_wait为什么是2MSL的时间长度(掌握)

为了保证客户端发送的最后一个ACK报文段能够到达服务器。这个ACK报文段可

能丢失,因而使在Last-ACK状态的服务器收不到对已发送的FIN+ACK报文段的确认。

服务器就会超时重传这个报文段,而客户端就能在2MSL时间内收到这个重传的

FIN-ACK报文段。接着客户端重传一个确认,重新启动2MSL计时器。2MSL的意义是,

经过2MSL后,所有的报文都会消失,不会影响下一次连接。最后客户端和服务器端都

能正常进入到CLOSED状态。如果服务器端在TIME-WAIT状态下不等待一段时间,而

是在发送完ACK报文段就立即释放连接,那么客户端就无法收到服务器重传的

FIN_ACK报文段,因而也就不会再发送一个报文段,这样服务器就无法进入CLOSED

状态

11、get、post的区别(掌握)

(1)get将数据放在url后面,post将数据放在报文体

(2)url长度有限制,报文体长度没有限制

(3)get将数据放在url后面,信息并不安全

12、说一下https,为什么安全,具体说一下https建立连接的流程(掌握)

为什么安全:

(1)http是是明文传输,https则是具有安全性的tsl加密传输协议。

(2)https除了三次握手以外,还要进行ssl握手,协商加密使用对称密钥

(3)https需要服务端申请证书,浏览器端安装根证书

https建立连接的流程

(1)在使用HTTPS是需要保证服务端配置正确了对应的安全证书

(2)客户端发送请求到服务端

(3)服务端返回公钥和证书到客户端

(4)客户端接收后会验证证书的安全性,如果通过则会随机生成一个随机数,用公钥

对其加密,发送到服务端

(5)服务端接受到这个加密后的随机数后会用私钥对其解密得到真正的随机数,随

后用这个随机数当做私钥对需要发送的数据进行对称加密

(6)客户端在接收到加密后的数据使用私钥(即生成的随机值)对数据进行解密并且

解析数据呈现结果给客户

(7)SSL加密建立

13、创建一个简单tcp服务器需要的流程(掌握)

(1)socket创建一个套接字

(2)bind绑定ip和port

(3)listen使套接字变为可以被动链接

(4)accept等待客户端的链接

(5)write/read接收发送数据

(6)close关闭连接

14、什么是粘包,怎么设计避免粘包(掌握)

(1)发送端需要等缓冲区满才发送出去,造成粘包

(2)接收方不及时接收缓冲区的包,造成多个包接收

解决办法:让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,

然后接收端来一个死循环接收完所有数据

ACK机制:

由于通信过程的不可靠性,传输的数据不可避免的会出现丢失、延迟、错误、重复

等各种状况,TCP协议为解决这些问题设计了一系列机制。这个机制的核心,就是发送

方向接收方发送数据后,接收方要向发送方发送ACK(回执)。如果发送方没接收到正

确的ACK,就会重新发送数据直到接收到ACK为止。比如:发送方发送的数据序号是

seq,那么接收方会发送seq + 1作为ACK,这样发送方就知道接下来要发送序号为seq +

1的数据给接收方了。

15、UDP的connect函数(掌握)

UDP的connect没有三次握手过程,内核只是检测是否存在立即可知的错误,记录

对端的的IP地址和端口号,然后立即返回调用进程。

16、HTTP2.0有哪些改动(掌握)

HTTP 2.0 的出现,相比于 HTTP 1.x ,大幅度的提升了 web 性能。在与 HTTP/1.1

完全语义兼容的基础上,进一步减少了网络延迟。

(1)多路复用允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息。

(2)二进制分帧:在应用层(HTTP/2)和传输层(TCP or UDP)之间增加一个二进制分

帧层。将所有传输的信息分割为更小的消息和帧(frame),并对它们采用二进制格式的

编码 ,其中 HTTP1.x 的首部信息会被封装到 HEADER frame,而相应的 Request Body

则封装到 DATA frame 里面。http1.x的解析是基于文本。基于文本协议的格式解析存在

天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不

同,只认0和1的组合。基于这种考虑http2.0的协议解析决定采用二进制格式,实现方

便且健壮。

(3)首部压缩:http1.x的header由于cookie和user agent很容易膨胀,而且每次都

要重复发送。http2.0使用encoder来减少需要传输的header大小

(4)服务端推送:http2.0能通过push的方式将客户端需要的内容预先推送过去

17、HTTP1.0、HTTP1.1的区别(掌握)

(1)长连接(Persistent Connection):HTTP1.1支持长连接和请求的流水线处理,在

一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,

在HTTP1.1中默认开启长连接keep-alive,一定程度上弥补了HTTP1.0每次请求都要创

建连接的缺点。HTTP1.0需要使用keep-alive参数来告知服务器端要建立一个长连接。

(2)节约带宽:HTTP1.0中存在一些浪费带宽的现象,例如客户端只是需要某个对

象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能。HTTP1.1支

持只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务

器,则返回100,客户端接收到100才开始把请求body发送到服务器;如果返回401,

客户端就可以不用发送请求body了节约了带宽。

(3)HOST域:在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,

请求消息中的URL并没有传递主机名(hostname),HTTP1.0没有host域。随着虚拟主

机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),

并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都支持host域,且请求消

息中如果没有host域会报告一个错误(400 Bad Request)。

(4)缓存处理:在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做

为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,

If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。

18、子网掩码的作用(掌握)

(1)一是用于屏蔽IP地址的一部分以区别网络标识和主机标识,并说明该IP地址

是在局域网上,还是在远程网上。

(2)二是用于将一个大的IP网络划分为若干小的子网络。

19、消息队列技术的优点(掌握)

(1) 解耦: 传统模式的缺点:系统间耦合性太强。中间件模式:将消息写入消息队

列,需要消息的系统自己从消息队列中订阅,从而系统A不需要做任何修改

(2) 异步:传统模式缺点:一些非必要的业务逻辑以同步的方式运行,太耗时间。

中间件模式:将消息写入消息队列,非必要的业务逻辑以异步的方式运行,以加快

响应速度

(3) 削峰:传统模式缺点:并发量大的时候,所有的请求直接怼到数据库,造成数

据库连接异常。中间件模式:系统A慢慢的按照数据库能处理的并发量,从消息队列中

慢慢拉取消息。

20、md5是什么(掌握)

md5是一种信息摘要算法,它在应用中经常使用MD5值来验证一段数据有没有被

篡改。

在数据的发送方将原始数据生成出MD5值,然后把原始数据连同其MD5值一起传

给接收方,接收该收到数据后,先将原始数据用MD5算法生成摘要信息,然后再将此

摘要信息与发送方发过来的摘要信息进行比较,如果一致就认为原始数据没有被修改,

否则原始数据就是被修改过了。

21、http协议的特性(掌握)

HTTP 协议一共有五大特点:1、支持客户/服务器模式;2、简单快速;3、灵活;4、

无连接;5、无状态。

无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到

客户的应答后,即断开连接。采用这种方式可以节省传输时间。

无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。即

我们给服务器发送 HTTP 请求之后,服务器根据请求,会给我们发送数据过来,但是,

发送完,不会记录任何信息。

22、http中常见的文件格式有哪些(掌握)

text/html: HTML格式

text/plain:纯文本格式

image/jpeg:jpg图片格式

application/json: JSON数据格式

application/x-www-form-urlencoded: form表单数据被编码为key/value格式发送到

服务器(表单默认的提交数据格式)

multipart/form-data: 在表单中进行文件上传时使用

23、短连接、高并发的网络连接应该怎么办?(大量TIME_WAIT的解决方案)(掌握)

TIME_WAIT状态是主动断开连接的一方产生的,客户端处于TIME_WAIT状态的

话问题不大,如果服务器产生大量TIME_WAIT状态的连接,就会大大降低服务器的响

应速度等性能问题,根本原因是一些端口号以及socket地址被占用而得不到释放。

(1)C/C++中提供了一个接口,如果服务器重启时需要对端口号以及socket地址进

行复用,从而避免了TIME_WAIT状态

(2)设置linux系统参数

_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,

启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;

_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的

TCP连接,默认为0,表示关闭;

_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,

默认为0,表示关闭。

_fin_timeout 修改系默认的 TIMEOUT 时间

24、syn洪泛攻击,如何应对(掌握)

A(攻击者)发送TCP SYN,SYN是TCP三次握手中的第一个数据包,而当这个

服务器返回ACK以后,A不再进行确认,那这个连接就处在了一个挂起的状态,也就

是半连接的意思,那么服务器收不到再确认的一个消息,还会重复发送ACK给A。这

样一来就会更加浪费服务器的资源。A就对服务器发送非法大量的这种TCP连接,由于

每一个都没法完成握手的机制,所以它就会消耗服务器的内存最后可能导致服务器死机,

就无法正常工作了。更进一步说,如果这些半连接的握手请求是恶意程序发出,并且持

续不断,那么就会导致服务端较长时间内丧失服务功能——这样就形成了DoS攻击。这

种攻击方式就称为SYN泛洪攻击。

那么我们如何去防范这种SYN攻击呢?

其实最常用的一个手段就是优化主机系统设置。比如降低SYN timeout时间,使得

主机尽快释放半连接的占用或者采用SYN cookie设置,如果短时间内收到了某个IP的

重复SYN请求,我们就认为受到了攻击。我们合理的采用防火墙设置等外部网络也可以

进行拦截。

25、略解TCP乱序和丢包(掌握)

Sequence Number: 顺序号,意即数据包的序号,主要用来解决数据包乱序问题。

Acknowledgement Number:确认号,意即数据包用来进行双端消息确认的号码,主

要用来解决网络传输过程中,数据丢包的问题。

TCP传输数据时,A主机第一次传输1440个字节,seq=1,那么第二次时seq = 1441,B

拼接数据就是根据seq进行拼接的,seq数字不断累加避免了乱序.B主机收到第一次数据

包以后会返回ack = 1441. A主机收到B的ack = 1441时,就知道第一个数据包B已收到.

如果B没有收到第一次的数据包,那么B再收到A的数据包时,他就会发ack = 1回去,A

收到B的回复,发现B没有收到第一次数据包,就会重发第一次数据包,这样就可以防止丢

包.

26、网络调试的工具(掌握)

Ping命令

Nslookup(name server lookup)是一个用于查询因特网域名信息或诊断DNS 服务器

问题的工具.

Fiddler(中文名称:小提琴)是一个HTTP的调试代理,以代理服务器的方式,监

听系统的Http网络数据流动,Fiddler可以也可以让你检查所有的HTTP通讯,设置断点,

以及Fiddle所有的“进出”的数据(我一般用来抓包),Fiddler还包含一个简单却功能强

大的基于JScript .NET事件脚本子系统,它可以支持众多的HTTP调试任务。

网站压力测试工具——webbench

数据库

1、数据库事务以及四个特性(掌握)

数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些

操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事

务结束之间执行的全部数据库操作组成。数据库事务数数据库最小逻辑单元。

四个特性:

(1)原子性(Atomicity):原子性是指事务包含的所有操作要么全部成功,要么

全部失败回滚。失败回滚的操作事务,将不能对事务有任何影响。

(2)一致性(Consistency):一致性是指事务必须使数据库从一个一致性状态变换

到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

例如:A和B进行转账操作,A有200块钱,B有300块钱;当A转了100块钱给B之

后,他们2个人的总额还是500块钱,不会改变。

(3)隔离性(Isolation):隔离性是指当多个用户并发访问数据库时,比如同时访

问一张表,数据库每一个用户开启的事务,不能被其他事务所做的操作干扰(也就是事务

之间的隔离),多个并发事务之间,应当相互隔离。例如同时有T1和T2两个并发事务,

从T1角度来看,T2要不在T1执行之前就已经结束,要么在T1执行完成后才开始。将

总的来说,CPU从内存中一条一条地取出指令和相应的数据,按指令操作码的规定,对数据

多个事务隔离开,每个事务都不能访问到其他事务操作过程中的状态;就好比上锁操作,

只有一个事务做完了,另外一个事务才能执行。

(4)持久性(Durability):持久性是指事务的操作,一旦提交,对于数据库中数

据的改变是永久性的,即使数据库发生故障也不能丢失已提交事务所完成的改变。

2、数据库三大范式(掌握)

第一范式(1NF):数据表中的每一列(每个字段)必须是不可拆分的最小单元,

也就是确保每一列的原子性;

第二范式(2NF):满足1NF后,要求表中的所有列,都必须依赖于主键,而不能

有任何一列与主键没有关系,也就是说一个表只描述一件事情;

第三范式(3NF):必须先满足第二范式(2NF),要求:表中的每一列只与主键

直接相关而不是间接相关,(表中的每一列只能依赖于主键);

3、事务的隔离级别(掌握)

事务的隔离性就是指,多个并发的事务同时访问一个数据库时,一个事务不应该被

另一个事务所干扰,每个并发的事务间要相互进行隔离。

读未提交(Read Uncommitted):因为没有行级共享锁,会出现脏读

读提交(Read Committed):通过行级共享锁,解决了脏读问题,但因为事务没有

加锁,导致前后读取数据不一致,即不可重复读

可重复读(Repeated Read):通过事务加锁,解决了不可重复读问题,但因为表没

有加锁,会出现幻读的情况,比如多了一行数据

串行化(Serializable):可解决脏读、不可重复读、幻读问题,通过对表直接加锁

的方式,但数据库的读取效率降低。

4、什么是数据库索引(掌握)

索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数

据库表中的特定信息。与在表中搜索所有的行相比,索引有助于更快地获取信息。唯一、

不为空、经常被查询的字段适合建立索引

5、索引类型与索引模型(掌握)

普通索引:哈希表、红黑树;唯一索引:比如设定学号为索引;主键索引:设定主

键作为索引;联合索引:多个字段共同索引;全文索引:查找关键字。

索引模型:哈希表、红黑树、B树、B+树

6、什么情况下数据库索引会失效(掌握)

(1)如果条件中有or,即使其中有条件带索引也不会使用(要想使用or,又想让

索引生效,只能将or条件中的每个列都加上索引)

(2)不符合最左匹配原则

(3)like查询是以%开头

(4)如果mysql估计使用全表扫描要比使用索引快,则不使用索引

7、引起慢查询的常见原因及一些解决方案(掌握)

(1)没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷)

(2)锁或者死锁(这也是查询慢最常见的问题,是程序设计的缺陷)

(3)查询语句不好,没有优化

(4)网络速度慢

(5)内存不足

解决方案:

(1)根据查询条件,建立索引,优化 索引、优化访问方式

(2)优化锁。可以使用乐观锁、读写锁

(3)优化查询语句

(4)提升网络速度

(5)扩大服务器内存

8、聚簇索引与非聚簇索引(掌握)

聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据

非聚簇索引:将数据存储于索引分开结构,索引结构的叶子节点指向了数据的对应

9、数据库主键和外键(掌握)

(1)主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年

龄。

身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证号是主键。

(2)外键用于与另一张表的关联。是能确定另一张表记录的字段,用于保持数据的

一致性。

比如,A表中的一个字段,是B表的主键,那他就可以是A表的外键。

10、mysql知道哪些存储引擎,它们的区别(掌握)

MyISAM、InnoDB。

InnoDB 支持事务、支持所有隔离级别、行级锁、外键关联、灾难恢复性好、索引

和数据是在一起的、用的B+树。不保存行列的信息,使用select需要扫描全表,查找慢

些。

MyISAM 不支持事务、不支持行级锁、外键关联,灾难恢复性差、在读写的时候需

要锁住整个表,效率低些。但是查找的时候保持行列信息,通过select可以查找相对比

较快,索引和数据是分开的、用的B+树。

11、mysql的四种日志(掌握)

错误日志:记录mysql运行过程ERROR,WARING等信息,系统出错或某条记录

出问题可查看ERROR日志。

日常运行日志:记录mysql中每条请求数据。

二进制日志:binlog,包含一些事件,数据库的改动等。

慢查询日志:用于mysql的性能调优。

12、mysql主从复制(掌握)

主从复制(也称 AB 复制)允许将来自一个MySQL数据库服务器(主服务器)的

数据复制到一个或多个MySQL数据库服务器(从服务器)。实现数据库的读写分离,

主数据库主要进行写操作,而从数据库负责读操作。同时数据库有多个副本,也可保证

数据库安全,主服务器如果出问题,可以将从服务器升级为主服务器。

三种复制方式

-- 基于SQL语句的复制(statement-based replication, SBR),

-- 基于行的复制(row-based replication, RBR),

-- 混合模式复制(mixed-based replication, MBR)。

13、怎么优化查询(掌握)

索引优化(选择合适索引、索引避免失效),分库分表,读写分离

14、什么是redis(掌握)

Redis 是一个基于内存的高性能key-value数据库。整个数据库统统加载在内存当中

进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,

Redis的速度快。支持丰富数据类型。支持事务。Redis的主要缺点是数据库容量受到物

理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较

小数据量的高性能操作和运算上。

Redis支持的数据类型:

string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序

集合)。

15、Redis怎么实现高效缓存(掌握)

为了提供网站的负载能力,需要将一个访问频路较高,且经过复杂计算或者IO资

源消耗较大的操作的结果缓存起来,并设置一个失效时间。每次用户访问的时候,先检

查该键是否存在,如果存在直接获取该元素并返回,如果不存在,则经过一系列计算并

将结果缓存,设置失效时间,在返回给用户

16、Redis持久化有哪几种方式,怎么选(掌握)

Redis是一种高级key-value数据库。它跟memcached类似,不过数据可以持久化。

Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上。redis

提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录

定时dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原

理是将Reids的操作日志以追加的方式写入文件)。

RDB是定期将数据写入磁盘,当redis出现故障时,有一部分内存数据肯定会丢失。

而AOF是以日志的方式追加,数据丢失会少很多。对于同一份数据来说,AOF 日志文

件通常比 RDB 数据快照文件更大,数据恢复慢一些。

1. 不要仅仅使用 RDB,因为那样会导致你丢失很多数据

2. 也不要仅仅使用 AOF,因为那样有两个问题,第一,你通过 AOF 做冷备,没

有 RDB 做冷备,来的恢复速度更快; 第二,RDB 每次简单粗暴生成数据快照,更加健

壮,可以避免 AOF 这种复杂的备份和恢复机制的 bug。

3. redis 支持同时开启开启两种持久化方式,我们可以综合使用 AOF 和 RDB 两种

持久化机制,用 AOF 来保证数据不丢失,作为数据恢复的第一选择; 用 RDB 来做不

同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快

速的数据恢复。

17、Redis对于过期键的清除策略(掌握)

被动删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个

过期key

主动删除:由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动

淘汰一批已过期的key

当前已用内存超过maxmemory限定时,触发主动清理策略

18、Redis单线程为什么快(掌握)

(1)完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。

(2)采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多

线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有

因为可能出现死锁而导致的性能消耗

(3)使用多路I/O复用模型,非阻塞IO

19、Redis如何实现高可用(掌握)

(1)主从复制数据:实现数据库的读写分离,主数据库主要进行写操作,而从数据

库负责读操作。

(2)哨兵机制:监控(哨兵(sentinel) 会不断地检查你的Master和Slave是否运作

正常)、提醒(当被监控的某个Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理

员或者其他应用程序发送通知)、自动故障迁移(当一个Master不能正常工作时,哨兵

(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的

Master)

20、Redis缓存穿透、缓存击穿、缓存雪崩(掌握)

缓存穿透:是指查询一个数据库一定不存在的数据。正常的使用缓存流程大致是,

数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,

并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。参数传入对

象主键ID根据key从缓存中获取对象如果对象不为空,直接返回如果对象为空,进行数

据库查询如果从数据库查询出的对象不为空,则放入缓存(设定过期时间)想象一下这

个情况,如果传入的参数为-1,会是怎么样?这个-1,就是一定不存在的对象。就会每

次都去查询数据库,而每次查询都是空,每次又都不会进行缓存。假如有恶意攻击,就

可以利用这个漏洞,对数据库造成压力,甚至压垮数据库。

解决办法:如果从数据库查询的对象为空,也放入缓存,只是设定的缓存过期时间

较短,比如设置为60秒

缓存击穿:是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点

进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就

像在一个屏障上凿开了一个洞。

解决办法:让缓存永不过期。

缓存雪崩:是指在某一个时间段,缓存集中过期失效。那么访问查询都落到了数据

库上,对于数据库而言,就会产生周期性的压力波峰。

解决办法:热门key缓存时间长一些,冷门key缓存时间短一些

21、Redis渐进式rehash(掌握)

在redis的具体实现中,使用了一种叫做渐进式哈希(rehashing)的机制来提高字典的

缩放效率,避免 rehash 对服务器性能造成影响,渐进式 rehash 的好处在于它采取分而

治之的方式, 将 rehash 键值对所需的计算工作均摊到对字典的每个添加、删除、查找

和更新操作上, 从而避免了集中式 rehash 而带来的庞大计算量。

22、Redis相比memcached有哪些优势(掌握)

(1)memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富

的数据类型

(2)redis的速度比memcached快很多

(3)redis可以持久化其数据

嵌入式面试知识点大全(春秋招必背)

本文发布于:2024-09-21 15:31:21,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/1726903881435494.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:进程   数据   函数   内存   线程   使用   访问
留言与评论(共有 0 条评论)
   
验证码:
排行榜

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23