实习
第一面准备
提问相关
操作系统有哪些功能
- 进程管理:
- 进程调度、进程同步和通信、多任务处理
- 内存管理:
- 内存分配、虚拟内存技术、内存保护
- 文件系统管理:
- 文件存储、目录管理、文件保护和权限:
- 设备管理
- 设备驱动程序、设备操作、IO操作管理
- 网络管理
- 网络连接、数据传输、网络共享
CLI运行一个用户程序整个过程发生了什么?
- 命令解析,查找对应的可执行文件
- 在环境变量path中寻找
- 创建新进程和资源分配
- 创建新进程:通过**fork()**系统调用,复制当前进程的所有内容,创建当前进程的副本的子进程
- 子进程执行程序:执行**exec()**系统调用,将自身的代码和数据替换为目标程序的代码和数据,子进程变成用户要执行的程序
- 分配资源:为新进程分配内存、文件描述符、CPU运行时间
- 文件描述符会继承父进程的,重新针对当前进程分配内存空、加入CPU运行队列
- 加载程序
- 将可执行文件加载到内存中
- 加载器:将指令和数据加载到内存的适当位置
- 动态链接:加载动态链接库到进程的地址空间
- 程序开始执行
- 加载完成后,新进程开始执行程序的入口main函数,等待进程调度
- 程序终止和资源清理
- 释放资源、进程表更新(进程表中移除该数据)、父进程通知调用wait来获取子进程的终止状态
- 显示输出和返回状态码
程序怎么从磁盘的二进制字节码进入内存变成进程的?
- 查找并读取可执行文件
- 加载器工作
- 读取可执行文件头(确定文件结构)、验证文件格式、解析段表(确定数据段、代码段的位置和大小)
- 内存分配
- 分配虚拟内存、设置内存映射
- 加载段到内存
- 懒加载或者立即加载
- 动态链接
- 设置运行环境
- 初始化堆栈
- 设置程序的入口点
- 执行程序
TCP/IP五层是怎么封装的?
- 应用层
- 生成数据,例如一个HTTP请求,数据格式化并准备传递给传输层。
- 传输层
- 数据分段,添加TCP头部,包含源端口、目标端口、序列号、校验和等信息。
- 形成传输层数据单元(segment)
- 网络层
- 网络层(如IP)在传输层数据单元前添加IP头部,包含源IP地址、目标IP地址、协议类型、校验和等信息。
- 形成数据包(packet)
- 数据链路层
- 数据链路层(如以太网)在网络层数据包前添加帧头,帧头包含源MAC地址、目标MAC地址、类型字段等信息。
- 形成数据帧(frame)。
- 物理层
- 数据帧被转换为物理信号(如电信号、光信号)并通过物理介质传输。
应用层数据
↓
传输层封装(TCP头部)
↓
TCP段
↓
网络层封装(IP头部)
↓
IP包
↓
数据链路层封装(帧头和帧尾)
↓
以太网帧
↓
物理层传输(物理信号)
协程和线程的区别
- 切换开销
- 线程调度是由内核负责,协程调度是由用户自己负责。协程的切换比线程快,因为不需要从用户态切换到内核态。
- 线程切换改变的寄存器和状态量比协程要多很多。
- 调度方式
- 线程是抢占式调度,频繁切换线程,系统开销大。
- 协程是协商式调度,协程执行完毕,主动释放CPU,切换次数少,性能高。
- 内存大小
- 线程的栈在创建时就已经制定了,8MB,协程的栈是KB级别的。线程过多,占据的资源会比较多,导致系统崩溃,协程可以成千上百。
- 线程栈是固定大小的,协程的展示可以收缩和扩容的。
如何书写结构体,运行效率更高
- 内存对齐和填充
- 处理器从内存读取数据时,通常以块(如4字节或8字节)为单位进行。合理安排内存,减少填充时间,减少内存访问时间。
- 缓存局部性
- 尽量将可能一起使用的成员放在一起,缓存命中率高。
- 避免不必要的嵌套
- 减少结构体的嵌套
- 使用位域优化
- 对于特定小范围数据,限定其使用的位的数量
- 使用编译器优化
- 编译器选项:使用编译器提供的优化选项和指令(如__attribute__((packed)))来优化结构体
C++函数调用为什么使用栈来实现
- 栈是一种后进先出(LIFO)的数据结构,函数调用过程具有天然的LIFO特性:一个函数调用可能会触发另一个函数调用,而每个函数在完成时需要返回到调用它的函数。
- 自动管理内存
- 简单高效:
- 只需要调整栈指针就能实现栈帧的分配和释放
- 递归支持
- 多线程支持:
- 每一个线程有自己的栈空间,独立管理各自的函数调用和返回,互不干扰。
linux和window之间进程管理的区别
- 进程模型
- 在Linux中,
- 进程和线程都是通过task_struct结构体来管理的。线程是轻量级进程,它们共享同一个进程的资源。
- 通过fork或者clone创建一个进程,新建进程是父进程的一个子进程
- windows
- 在Windows中,进程是包含一个或多个线程的容器。每个进程都有一个进程控制块(PCB),线程有各自的线程控制块(TCB)。
- Windows使用CreateProcess()函数创建新进程。这个函数创建一个新的进程及其主线程,并初始化新进程的执行环境。
死锁产生以及破坏死锁的条件
- 两个以上进程并发执行,争夺资源相互等待的现象。
- 互斥条件
- 持有并等待
- 不剥夺条件
- 环路等待
- 避免死锁的条件
- 加锁顺序:使用资源的有序分配法来破坏环路等待
- 加锁时限:请求某一个资源超过一段时间没有获取到,自动释放。
- 死锁检测:当一个线程请求锁失败时,这个线程可以遍历资源的关系图看看是否有死锁发生。
进程通信的几种方式,哪种最快
- 管道通信
- 消息队列
- 共享内存:最快
- 信号
- 信号量
MySQL索引,怎么建,底层原理,模糊查询走不走索引
- 索引建立
- 通过CREATE INDEX语句创建索引,除了主键索引,其他都是要手动创建
- 索引底层原理
- B+树索引实现,B+树的基本特征
- 索引查找过程
- 模糊查询与索引
- 模糊查询不利于索引的使用。因为模糊查询的匹配方式可能导致索引失效,使得MySQL无法有效地利用索引加速查询
MySQL事务怎么防止中断日志
- WAL(Write-Ahead Logging)机制
- 数据库的持久化设置
- 文件系统缓存与硬件缓存
了解线段树嘛
- 平衡二叉查找树,根节点表示一个完整的单元区间,内部节点,将整个区间划分成更小的区间。
- 实现数据的查找
C++面向对象的设计原则
- 单一职责原则
- 一个类应该只负责一个功能领域的事务
- 开放-封闭原则
- 应该对扩展开放,对修改封闭
- 里氏替换原则(Liskov Substitution Principle,LSP)
- 子类型必须能够替换其基类型而不影响程序的正确性
- 依赖倒置原则(Dependency Inversion Principle,DIP)
- 高层模块依赖于抽象原则
- 接口隔离
- 最小知识原则
- 合成/聚合复用原则
算法相关
medium 最大雨水面积
- 具体链接
- 这里再补一个反正法,证明这个方法是最优的
三数之和
考试的最大困扰度
第一面结果
- 不知道明天面试的怎么样,一会睡前再把所有的看过的八股题目全部都过一遍,然后早上起来在背一遍。
- 总结,如果还想投华为,就需要对一门语言十分精通,华为主要是语言的特性问的比较多,并不会问很多八股内容。所以,并不需要花太多时间去准备八股的内容。除此之外,还是需要好好刷一下算法,尤其是做过的题目,他会直接给你一个leetcode链接,然后让你开始现场写。
- 其实心里还是有点失落,毕竟很想去华为,但是自己确实准备的不怎么样,好好准备一下秋招。下面回顾一下整个面试过程中的所有的问题
提问环节
以后应该不会看C++了,这里暂时就不准备整理了,以后的我的语言栈就是java。
C++的内存管理
*
介绍一下虚函数和纯虚函数,有什么特性
定义:虚函数(Virtual Function)是指在基类中使用关键字 virtual 修饰的成员函数。它允许在派生类中重新定义(覆盖)这个函数。
特点:
动态绑定:使用虚函数可以实现动态绑定(Dynamic Binding),即在运行时确定调用哪一个函数版本,而不是在编译时。这使得程序可以在运行时根据实际对象的类型来调用相应的函数。
多态性:虚函数是实现多态性的基础。通过虚函数,基类的指针或引用可以调用派生类的函数版本。
基类和派生类:在基类中声明为虚函数的成员函数,在派生类中可以重新定义(覆盖)。覆盖后的函数也默认是虚函数,不需要再显式使用 virtual 关键字。
纯虚函数
定义:纯虚函数(Pure Virtual Function)是指在基类中声明,但不提供实现的虚函数。纯虚函数在声明时使用 = 0 语法。
特点:
抽象类:包含至少一个纯虚函数的类称为抽象类(Abstract Class)。抽象类不能直接实例化对象。
必须覆盖:派生类必须覆盖(实现)纯虚函数,否则派生类也将成为抽象类,不能实例化。
接口设计:纯虚函数常用于设计接口,强制派生类实现某些特定的功能。
智能指针的相关操作
python有哪些数据结构
python中的list有什么特性
总结
- 以后如果还是想去华为,就得专精一门语言,把关于语言的所有的八股都好好看一下,了解语言最底层的一些特定还有一些特征,要专精。他是不限制语言的,所以要好好准备一门语言,专精,刚好也减轻我的一部分压力。然后数据库和redis也得好好准备一下。
- 本次面试最难受的就是,我知道他的套路,让我选择了,但是我没有一个语言是擅长的,只能说给你选了三天路,但是你一条路都不会,所以只能被毙掉,情理之中。
- 下一步好好看看java,专精一门语言即可,不要再其他语言上花时间了。