## 腾讯 #### 后台开发一面 8.30 - 说一下C++的内存模型 - 栈区:系统自动维护的区域,主要用来存放局部变量、函数参数等 - 堆区:程序员维护的区域,需要程序员显示的分配和释放。 - 全局/静态存储区:程序中的全局变量和静态变量都会被分配到这个区域 - 常量存储区:常量都存放在这里,不允许修改 - 代码区:存放代码的区域,不允许修改,可以执行 - malloc 和 new 的区别 - malloc 是和 free 是标准函数库,用来分配和释放空间,但是 free 函数并不会执行对象的析构函数,处理对象的时候具有一定的风险性。 - new 和 delete 是关键字,也可以用来分配和释放空间,delete 会执行对象的析构函数,适合处理对象。 - malloc 返回的是 void 类型的指针,new 返回的是对于类型的指针 - 说一下重载和重写 - 重载是一种在同范围内定义的同名函数之间的关系,他们的函数名称相同,参数列表具有差异,比如参数个数不同,参数类型不同 - 重写是指在派生类中覆盖父类的同名函数,要求是函数名称、参数、返回值全部相同 - **静态分配和动态分配** - 静态分配是指全局变量、静态变量等变量的分配,这些过程发生在编译期 - 动态分配是指利用 malloc 或 new 的分配,这些过程发生在运行时 - **C++的内存对齐规则** - 基本数据类型的对齐值就是其 sizeof 获取的值 - 数据成员对齐规则:结构中:第一个数据成员的偏移量为0,以后每个数据成员按照#pragma pack(默认为 4)指定的数值和自身长度的较小值来对齐。 - 结构的对齐规则:在数据成员完成各自的对齐之后,结构本身也要对齐,对齐值取#pragma pack指定的数值和结构最大数据成员长度较小的那个 - **说一说进程、线程、协程** - 进程是资源分配的基本单位;在切换进程时需要陷入内核态,因为切换者是操作系统,切换时需要保存进程的 **CPU 环境(栈、寄存器,页表,文件描述符等)**,切换开销很大 - 线程是内核调度的基本单位;在切换线程的时候需要陷入和内核态,因为切换者是操作系统,切换时需要保持程序计数器、少量寄存器和栈的内容,切换开销较小 - 协程是用户态的轻量级线程,线程内部调度的最小单位;在切换协程时只需要在用户态,完全由用户来管理而不是操作系统,切换时只需要保持少量寄存器和栈的内容,切换开销最小 - **单核多线程需要上锁吗** - 需要,因为第一个线程读取一个公共变量之后继续执行很复杂的逻辑,此时中断的话,另一个线程可能会更改这个变量,这样就产生了数据错误 - 在浏览器地址栏输入一个URL后回车,背后会进行哪些技术步骤 - 解析和拆分 url,主要的部分有:协议(http 或者 https)、域名、端口号、请求的参数等域名解析 - 域名解析,请求域名服务器将域名映射成对应的 ip 地址 - 建立 Tcp 链接,通过三次握手来简历 Tcp 链接 - 发起 http 请求,浏览器向服务器发起 http 请求 - 服务器处理 http 请求 - 服务器响应请求 - 浏览器接收到请求之后渲染界面给用户 - **域名解析的具体过程** - 首先查看浏览器的本地缓存,看有没有映射 - 再查看操作系统的缓存 - 本地主机文件查找(host 文件) - 两种解析方式:迭代解析和递归解析,迭代解析的时候是我们自己不断的去请求不同的 dns 服务器,迭代是本地域名服务器帮我们区请求 - 本地域名服务器是本地网络中的域名解析器 - 之后依次是**根域名服务器、顶级域名服务器、权威域名服务器** - **讲讲 IO 多路复用** - IO 多路复用是一种处理多个 I/O 事件的技术,提高系统的利用率,尝尝用来解决网络应用中同时处理多个客户端链接的问题,其重要有三种方式: - select每次调用都会将注册的文件描述符从用户空间拷贝到内核空间中去监听它们的可读可写异常等事件(开销较大)。且监听的文件描述符有上限。需要遍历文件描述符集合才能找到就绪的文件描述符 - poll 与 select 没有太多的区别,只是解决了文件描述符具有上限这个问题 - epoll 同时解决了开销问题和文件夹描述符上限问题,有新的文件描述符需要监听的时候只需要用epoll_ctl函数添加即可,并且在有就绪的文件描述符时,其也只会返回就绪的文件描述符 - epoll 同时支持触发出发和边缘触发;只要文件描述符就绪就会触发通知,如果用户一次性没读完或写完,下次内核还会继续通知。边缘触发只有在文件描述符的状态发生改变时才会通知,这意味着,我们需要一次性将数据写完或读完。select和 poll 都不支持边缘触发 - 边缘触发适用场景 - 应用程序需要长时间等待事件就绪。 - 应用程序需要处理大量的文件描述符或网络连接。 - 应用程序需要定期检查 I/O 状态并采取必要的操作。 - 边缘触发适用场景 - 应用程序需要实时响应 I/O 事件并尽快处理数据。 - 应用程序需要最小化处理 I/O 事件时的 CPU 开销。 - 应用程序需要确保不会重复处理同一事件。 - 有一个文件包含了大量的 8 为纯数字 QQ 号,现在让你找出不同 QQ号的个数; - 可以将 QQ 号抽象成一个数,用一个 bit 数组表示 QQ 号,比如第0 为 bit 表示数字 0,以此类推。 - bit 位为 1 表示这个 QQ 号前面已经出现过了 - **介绍下布隆过滤器** - 布隆过滤器是用来判断一个元素是否在一个集合的数据结构,具有高效的查询效率和内存占用,但会存在一定的误判率 - 布隆过滤器主要通过一组哈希函数和位数组来实现,以下是其特点 - 插入操作:将一个元素插入布隆过滤器时,通过 k 个哈希函数得到 k 个值,将位数组这个 k 个下标对应的为置 1 - 查询操作:通过 k 个哈希函数得到 k 个值,检查位数组 k 个下标的值是否全为 1 - 误判率:因为多个元素可能映射到同样的下标,存在误判的可能性。 #### 手撕代码 - [整数反转](https://leetcode.cn/problems/reverse-integer/) - [LRU缓存](https://leetcode.cn/problems/lru-cache/)