面试题(三)

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. 批量操作优化

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

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

相关推荐
Koi慢热5 分钟前
路由基础(全)
linux·网络·网络协议·安全
传而习乎15 分钟前
Linux:CentOS 7 解压 7zip 压缩的文件
linux·运维·centos
soulteary16 分钟前
突破内存限制:Mac Mini M2 服务器化实践指南
运维·服务器·redis·macos·arm·pika
爱吃青椒不爱吃西红柿‍️44 分钟前
华为ASP与CSP是什么?
服务器·前端·数据库
运维&陈同学2 小时前
【zookeeper01】消息队列与微服务之zookeeper工作原理
运维·分布式·微服务·zookeeper·云原生·架构·消息队列
是阿建吖!2 小时前
【Linux】进程状态
linux·运维
hzyyyyyyyu2 小时前
内网安全隧道搭建-ngrok-frp-nps-sapp
服务器·网络·安全
明明跟你说过2 小时前
Linux中的【tcpdump】:深入介绍与实战使用
linux·运维·测试工具·tcpdump
刽子手发艺2 小时前
WebSocket详解、WebSocket入门案例
网络·websocket·网络协议