面试题(三)

20、CA证书

服务器安装数字证书,客户端安装根证书

CA的颁发机构、有效期、签名、公钥、证书所有者

21、公钥和私钥有什么区别

22、三次握手 四次挥手 为什么要四次

服务端数据没有发送完,二三次不能合并

23、四次挥手完会立马关闭吗(会监听一段时间 这个时间具体是多少?)

2MSL,保证服务端接收到最后一个ACK正常关闭

24、tcp如何保持可靠传输

序列号、确认号、超时重传

窗口

拥塞控制:慢启动、窗口阈值、快恢复、快速重传

25、拥塞控制 流量控制

26、具体说一下拥塞窗口cwnd

27、为什么要分段和分页,分段和分页的优缺点

**分段(Segmentation)和分页(Paging)**是现代操作系统管理内存的两种主要方法,它们都有各自的优缺点,通常结合使用以获得更好的性能和灵活性。

1. 分段(Segmentation)

分段是内存管理的一种方式,将逻辑内存划分为不同的段(segment),每个段代表一个逻辑单位,如代码段、数据段或堆栈段。每个段有独立的基址和大小。

优点

  • 逻辑结构清晰:程序按照逻辑模块划分段,符合程序的自然结构,使得管理和访问更加直观。
  • 方便共享和保护:可以对不同段设置不同的访问权限,从而实现进程间的数据共享和内存保护。
  • 动态增长:段可以动态增长,特别适合某些需求不断增加的结构(如堆栈)。

缺点

  • 外部碎片:由于段的大小是可变的,随着段的分配和释放,内存中可能出现外部碎片,使得内存利用效率降低。
  • 管理复杂:段表较复杂,尤其是当段数较多时,管理段的基址和大小需要更多的资源。

2. 分页(Paging)

分页是另一种内存管理方式,它将物理内存和虚拟内存划分为固定大小的页(page)。虚拟地址空间被分成若干个等大小的页,而物理内存被分成等大小的页框(frame),虚拟页通过页表映射到物理页框。

优点

  • 无外部碎片:因为分页固定大小,内存分配和回收时不会产生外部碎片(即未被使用的大块内存)。
  • 灵活的内存管理:可以将程序的页分散放置在物理内存的不同位置,灵活管理内存。
  • 简单的内存保护:通过页表,每个页可以单独控制访问权限,易于实现内存保护和隔离。

缺点

  • 内部碎片:由于页的固定大小,可能会有部分内存没有被完全使用,产生内部碎片。
  • 页表开销:需要维护页表,当虚拟地址空间较大时,页表可能会占用较多内存,且频繁的页表查找会影响性能。

3. 分段和分页的结合

在许多现代操作系统中,分段和分页结合使用,发挥两者的优势。例如,内存可以先分为不同的段,每个段再划分为若干固定大小的页,这种方式既能避免分页产生的内存碎片,又可以利用分段的逻辑结构。

结合的优点

  • 减少碎片:结合分段和分页,可以避免外部碎片问题,同时也能更好地组织和保护内存。
  • 灵活的内存管理:结合两者的优点,既可以灵活调整段的大小,又可以使用分页进行细粒度的内存管理。

结合的缺点

  • 管理复杂度高:需要维护段表和页表两种数据结构,增加了内存管理的复杂性和开销。

总结

分段和分页各有优缺点,分段适合逻辑模块化的程序,分页则更擅长减少内存碎片并提供更灵活的内存管理。结合两者的方式能够更好地平衡这两者的缺点,实现高效的内存管理。

28、 vector list 区别

29、C++ 宏和内联函数区别,何时触发"优化"

在 C++ 中,宏和内联函数都可以在特定条件下触发优化,但它们的机制和触发优化的时机不同。

1. 宏 (Macros)

宏是在预处理阶段通过 #define 定义的文本替换。它们直接在编译前将代码片段替换为定义的内容,因此避免了函数调用的开销。

宏触发优化的时机:
  • 消除函数调用开销:由于宏是直接展开的,代码中不会涉及到函数调用,因此减少了调用的额外开销。
  • 纯文本替换:宏只是在代码中进行简单的替换,因此在频繁使用的地方可以通过减少函数调用来优化性能。

但由于宏是文本替换,它没有类型检查和作用域管理,可能引入难以发现的错误。

2. 内联函数 (Inline Functions)

内联函数通过 inline 关键字定义。它们与宏不同,会进行类型检查、作用域控制,并通过编译器决定是否进行内联展开。

内联函数触发优化的时机:
  • 消除函数调用:当编译器决定将内联函数展开时,函数调用将被替换为函数体代码,从而避免函数调用开销。这对于小型、频繁调用的函数尤为有效。
  • 编译器优化决策 :尽管使用了 inline 关键字,但是否内联最终由编译器决定。编译器会根据函数的复杂性、大小、以及是否递归等因素判断是否展开函数。
  • 类型检查和安全:与宏不同,内联函数具有类型安全性,编译器会确保函数使用的正确性,从而减少由于直接替换带来的潜在问题。

3. 优化触发的条件

无论是宏还是内联函数,优化触发的关键在于以下几个条件:

  • 函数的大小:小的函数更有可能被内联,因为其展开后带来的性能提升大于展开的成本。
  • 调用频率:在循环中或性能关键路径上频繁调用的函数,更有可能被编译器内联。
  • 编译器优化等级 :使用高等级优化选项(如 -O2-O3)时,编译器会更积极地尝试内联小型函数。
  • 代码复杂度:如果函数体过大或包含复杂的控制结构,编译器可能不会进行内联展开。

4. 宏与内联函数的区别

  • 安全性:内联函数比宏更安全,具有类型检查和作用域管理,避免了宏带来的潜在错误。
  • 编译器决策:宏总是直接替换,而内联函数是否展开则取决于编译器的判断。
  • 调试和维护:内联函数在调试时更易追踪,而宏的错误可能更难发现,因为它们是在预处理阶段完成替换的。

示例

宏示例

cpp 复制代码
#define SQUARE(x) (x * x)

使用 SQUARE(5 + 1) 会展开为 (5 + 1 * 5 + 1),得到错误的结果。

内联函数示例

cpp 复制代码
inline int square(int x) {
    return x * x;
}

调用 square(5 + 1) 会返回正确的 36,并且由于是内联函数,可能避免函数调用的开销。

结论

  • 可以通过消除函数调用直接展开代码,提升性能,但缺乏类型检查和作用域控制,可能带来风险。
  • 内联函数 提供更安全的替代方案,编译器在合适的情况下会进行内联优化,减少函数调用开销,提升性能。

通常,现代 C++ 更倾向于使用内联函数,因为它们在安全性、可维护性和调试方面相比宏有显著优势。

30、C++ 虚函数表的结构,是连续的吗,虚函数地址存放顺序

在 C++ 中,虚函数表vtable )通常存放在静态内存 区域或全局数据区 ,由编译器在程序的初始化阶段生成并管理。每个类只会有一个虚表,而每个包含虚函数的对象会包含一个指向该虚表的指针(vptr),通过它实现对虚函数的动态调用。

虚表存放的细节

  1. 静态区域:虚表是类级别的,而非对象级别,因此它是静态的,所有实例共享一个虚表。编译器会在类加载时将虚表分配在静态内存区域中,与全局或静态变量类似。因为虚表是不可变的(除非涉及动态装载的情况),所以存放在一个固定的、共享的区域能够有效节省空间。

  2. vptr的位置:每个包含虚函数的对象会在对象内部存储一个指向虚表的指针(vptr),这个指针通常位于对象的最前面。通过这个指针,程序能够在运行时找到虚表,从而通过虚表中的函数指针进行动态绑定,调用正确的虚函数。

运行时机制

  • 在程序运行时,当调用一个虚函数时,程序首先通过 vptr 找到对象所属类的虚表,并在虚表中找到对应函数的地址。这允许 C++ 实现运行时的多态性。

总结

虚函数表存放在静态的内存区域,由编译器在类定义时生成并初始化,而 vptr 则存储在每个对象中,指向该类的虚表,保证虚函数能够在运行时进行正确的动态调用。

31、 数据表「学号、姓名、分数、课程名、学分」如何优化

优化数据表「学号、姓名、分数、课程名、学分」的设计,可以从以下几个方面考虑:

1. 表的结构优化

  • 分表设计 :将信息拆分成多个具有更高内聚性的表,以避免数据冗余并提升查询效率。
    • 学生表(Student)
      • 学号(Primary Key)
      • 姓名
    • 课程表(Course)
      • 课程ID(Primary Key)
      • 课程名
      • 学分
    • 成绩表(Score)
      • 学号(Foreign Key)
      • 课程ID(Foreign Key)
      • 分数

2. 添加索引

为提高查询效率,在常用的查询字段上创建索引:

  • 学号索引:针对按学号查询的操作,建立索引可以快速定位学生。
  • 课程ID索引:针对按课程名或课程ID查询的操作,使用索引可以加速检索。

3. 考虑数据库规范化

  • 第一范式 (1NF):保证每个字段的值是不可再分的原子值,已满足。
  • 第二范式 (2NF):消除非主属性对部分主属性的依赖,分离成绩表。
  • 第三范式 (3NF):消除非主属性对非主属性的传递依赖,确保数据的独立性,姓名不依赖于成绩。

4. 冗余设计与缓存优化

如果需要提升查询性能,可以考虑添加适当的冗余字段或数据缓存:

  • 总学分冗余字段:如果频繁查询某学生的总学分,可以将总学分预先计算并缓存。
  • 缓存机制:使用数据库层面的缓存或分布式缓存系统(如 Redis)缓存学生成绩等常用数据,减少频繁的数据库查询压力。

5. 批量操作优化

对于频繁的批量插入、更新操作,可以使用事务处理或批量处理功能,减少操作的频次和锁的争用。

通过这些优化措施,可以提升表的性能和数据的一致性,并优化查询、插入等操作的效率。

相关推荐
鳄鱼皮坡4 分钟前
仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器
运维·服务器
菜包eo6 分钟前
二维码驱动的独立站视频集成方案
网络·python·音视频
即将头秃的程序媛16 分钟前
centos 7.9安装tomcat,并实现开机自启
linux·运维·centos
yzx99101324 分钟前
关于网络协议
网络·人工智能·python·网络协议
zsq41 分钟前
【网络与系统安全】域类实施模型DTE
网络·安全·系统安全
小Mie不吃饭41 分钟前
FastAPI 小白教程:从入门级到实战(源码教程)
运维·服务器
fo安方2 小时前
运维的利器–监控–zabbix–第三步:配置zabbix–中间件–Tomcat–步骤+验证
运维·中间件·zabbix
爱奥尼欧2 小时前
【Linux 系统】基础IO——Linux中对文件的理解
linux·服务器·microsoft
戒不掉的伤怀2 小时前
【Navicat 连接MySQL时出现错误1251:客户端不支持服务器请求的身份验证协议;请考虑升级MySQL客户端】
服务器·数据库·mysql
超喜欢下雨天2 小时前
服务器安装 ros2时遇到底层库依赖冲突的问题
linux·运维·服务器·ros2