######################################## 八股文 ######################################## 自我介绍 **************************************** 您好,我叫张龙涛。河南驻马店人,22 届新疆大学本科生。应聘的是研发工程师,非常感谢贵公司能给我这次机会。接下来我会从三个方面进行自我介绍: | 第一:我能够熟练使用 C++ 开发软件。并且阅读了 Effective C++、More Effective C++、深入理解 C++ 对象模型、C++ 编程思想以及 C++ 标准草案等书籍。能够写出来质量不错的代码。而且对多线程的掌握也比较好 | 第二:我在大学期间在各个方面都有所涉猎,比如 Python、爬虫、Django、React、Qt、Linux、数据库等。能熟练使用常用的设计模式,并且对反应式编程、面向数据编程、声明式编程也比较了解。因此我能够很快地学习、理解新知识并将其应用到实践中 | 第三:我在休闲的时候也会玩一些游戏。对它的实现也非常感兴趣,也乐于能够从事相关工作,研究游戏各种特效的实现方式等。我也非常希望能够加入贵公司并和同事们一起设计更多精品游戏 研发工程师:(C/C++ 方向) | 第一:我对 C/C++ 非常熟悉。并且阅读了大量相关的书籍。而且对多线程的掌握也比较好 | 第二:我在大学期间在各个方面都有所涉猎,比如 Java、Python、爬虫、Django、React、Qt、Linux等。能熟练使用常用的设计模式。因此我认为我可以很快地学习、理解新知识并将其应用到实践中 | 第三:我热爱编程,并且能够从中得到成就感。 开发工程师 | 第一:我对 C/C++ 非常熟悉。并且阅读了 Effective C++、More Effective C++、深入理解 C++ 对象模型、C++ 编程思想以及 C++ 标准草案等书籍。而且对多线程的掌握也比较好 | 第二:对 C++ 中常用的一些库,比如 stl, boost, Qt, spdlog, gtest 等都能熟练使用,而且项目中也有使用它们的经历 | 第三:我热爱编程,并且能够从中得到成就感。 测试开发: 您好,我叫张龙涛。河南驻马店人,22 届新疆大学本科生。应聘的是测试开发工程师,非常感谢贵公司能给我这次机会。接下来我会从三个方面进行自我介绍: | 第一:我大学期间做过多个项目,开发能力也得到了提升。对于 C++/Python/Java/HTML/Bash 等都有涉及 | 第二:我有单元测试的经历,对于 gtest 掌握的还不错,还做过一些压力测试,也有使用 Fillder(非得勒) 、 whistle(we so)和 SwitchyOmega 的经验 | 第三:对于 CI/CD 而言,我使用过 GitHub Action,而且对于 Docker 和 Docker-Compose 也比较擅长 你为什么能够胜任这个岗位 1. 开发能力得到了锻炼 2. 我相信自己的学习能力,可以快速上手 3. 沟通能力,很有耐心,有责任感,我认为这在测试中也是很重要的一些素质。 对转转有什么认识: 转转由腾讯与58集团共同投资二手交易平台,2021 年 6 月,转转集团完成了D1轮融资。国内二手电商领域唯一一家短期内获得两轮大规模现金融资的公司。估值超18亿美元 微信点赞功能: 功能测试:: 是否可以点赞 取消点赞 多次点赞会出现什么情况 多人点赞时的顺序是否按照时间顺序进行排列 点赞是否显示头像和名称 点赞之后能否进行评论 点赞之后退出该页面,再次进入朋友圈点赞消息是否还存在 多用户点赞,再次打开朋友圈是是否可以按照顺序看到是谁谁谁赞了我 接口测试:: 点赞之后相同好友是否收到提示信息 相同好友处的提示信息是否按照时间顺序 相同好友处的点赞是否显示头像和名称 兼容测试:: 电脑端和手机端是否都可以进行点赞和取消点赞功能 不同的移动端是否都可以行点赞和取消点赞功能(包括苹果,安卓) 可用性测试:: 弱网的时候进行点赞是什么情况 网络断开时是否可以点赞 用户点击点赞几秒后可以看到点赞成功,取消同理 多用户同时给我点赞时,我是否可以全部接收到提示消息 安全性测试:: 点赞是否会泄漏微信用户相关信息 有什么优点? #. 我学习能力比较强。比如说我中考的时候只考了二百多分,但是高考考了五百六十多。所以我人为我学习能力比较强 #. 我对技术有中孜孜不倦的精神。大一上学我为了学习操作系统,先后看了汇编语言、操作系统真相还原、一个六十四位操作系统的实现等书籍,并在一个学期内完成了相关的内容 有什么缺点: 在我决定投递贵公司时,我还没有 UE 的相关经验。但是这两天我一直在抽空学习 UE 相关的内容,而且也自己手动对 UE 源码进行了编译。接下来我会买相关的书籍更加系统地学习相关的内容,希望在进入实习期间时能够较为独立地完成项目 内存模型 **************************************** 在 C++ 中,虚拟内存分为代码段、数据段、BSS 段、堆区、栈区、文件映射区六部分。 - 代码段: 包括只读存储区和文本区,其中只读存储区存储字符串常量,文本区存储程序的机器代码。 - 数据段:存储程序中已初始化的全局变量和静态变量 - BSS 段:存储未初始化的全局变量和静态变量(局部 + 全局),以及所有被初始化为 0 的全局变量和静态变量。 - 堆区:调用 new/malloc 函数时在堆区动态分配内存,同时需要调用 delete/free 来手动释放申请的内存。 - 栈:使用栈空间存储函数的返回地址、参数、局部变量、返回值 - 映射区: 存储动态链接库以及调用 mmap 函数进行的文件映射 进程和线程的区别 **************************************** - 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程依赖于进程而存在。 - 进程之间的资源是相互隔离的。线程之间共享进程的资源(除了线程的栈) - 进程是资源分配的最小单位,线程是 CPU 调度的最小单位 - 进程的创建、撤销和切换的开销要高于线程 - 线程之间可以通过全局变量的方式进行通信,更加简单 - 进程调试简单;线程调试复杂。 - 进程间不会相互影响 ;线程挂掉将导致整个进程挂掉 - 进程适应于多核、多机分布;线程适用于多核 进程和线程的选择 **************************************** - 需要频繁创建的优先使用线程 - IO 繁忙的优先使用进程,计算繁忙的优先使用线程 - 需要分布式的时候使用进程 - 需要稳定性的时候使用进程 虚拟内存 **************************************** - 扩大地址空间 - 内存保护:每个进程运行在各自的虚拟内存地址空间,互相不能干扰对方。虚存还对特定的内存地址提供写保护,可以防止代码或数据被恶意篡改。 - 内存公平分配:采用了虚存之后,每个进程都相当于有同样大小的虚存空间。 - 共享代码:当不同的进程使用同样的代码时,物理内存中可以只存储一份这样的代码,不同的进程只需要把自己的虚拟内存映射过去就可以了 - 当进程通信时,可采用虚存共享的方式实现 - 许多程序的片段可以同时保存在内存中。当一个程序等待它的一部分读入内存时,可以把 CPU 交给另一个进程使用。在内存中可以保留多个进程,提高了系统的并发性 - 在程序需要分配连续的内存空间的时候,只需要在虚拟内存空间分配连续空间,而不需要实际物理内存的连续空间,提高了内存的利用率 内存调度算法 **************************************** OPT、FIFO、LFU、LRU、LRU-K、2Q、CLOCK IO 模型 **************************************** - 阻塞 IO:当用户线程发出 IO 请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出 CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除 block 状态。 - 非阻塞 IO:当用户线程发起一个 read 操作后,并不需要等待,而是马上就得到了一个结果。如果结果是一个 error 时,它就知道数据还没有准备好,于是它可以再次发送 read 操作。一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。非阻塞 IO 需要使用轮询的方式查看数据是否准备好 - 信号 IO:用户线程发起一个 IO 请求操作,会给对应的 socket 注册一个信号函数,然后用户线程会继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用 IO 读写操作来进行实际的 IO 请求操作。 - 异步 IO:当用户线程发起 read 操作之后可以直接去处理其它事件,而内核对 IO 进行处理,并在结束后发给进程一个信号 - IO 多路复用:一个线程可以管理多个套接字的状态,通过轮询的方式来检测是否有事件到达,并且对到达的事件逐一进行响应 另外有两个高性能 IO 模型: - Reactor:客户向线程注册事件,然后线程轮询是否有事件发生 - Proactor:当检测到有事件发生时,会新起一个异步操作,然后交由内核线程去处理,当内核线程完成 IO 操作之后,发送一个通知告知操作已完成。异步 IO 模型采用的就是 Proactor 模式 IPC **************************************** 共享内存、信号、信号量、套接字、管道、消息队列、DBus TCP 和 UDP **************************************** - UDP 功能及其有限,只有复用分用和差错校验两个功能。而 TCP 还提供了流量控制、拥塞控制、数据重传等功能 - UDP 是无连接的,TCP 在连接前必须经过三次握手 - UDP 尽最大努力传输,TCP 则保证按时有序的到达 - UDP 对报文不拆分、不合并,保留上面传下来的报文边界。TCP 的报文长度根据接受方窗口的大小确定 - UDP 首部只有 8 字节。TCP 有 20 个字节 - UDP 支持多点传输,TCP 是点对点传输 端口复用就是指 UDP 可以将数据发给不同的端口。分用就是多个端口可以通过 UDP 传输信息 TCP 如何保证数据可靠性 **************************************** - 序列号、确认应答、超时重传 - 窗口控制与快速重传 - 拥塞控制和流量控制 - 三次握手和四次挥手 为什么是三次握手 **************************************** - TCP 是全双工通信,两次握手只能确定单向数据链路是可以通信的,并不能保证反向的通信正常 - TCP 本来是和挥手一样四次,但是因为中间两次可以合并,说就变成了三次 为什么是四次挥手 **************************************** 因为客户端不想发数据的时候需要发送 FIN 信号并经过 ACK 确认。但是这时候服务段可能还需要发送数据,当服务段也发送 FIN 并得到 ACK 时才能保证链接已经断开 流量控制 **************************************** 流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收,是点到点的问题 发送窗口每收到一个 ACK 就将 cwnd 大小翻倍 拥塞控制 **************************************** 防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载 慢开始、拥塞避免、快速重传 GET 和 POST **************************************** 1、概括 对于 GET 方式的请求,浏览器会把 http header 和 data 一并发送出去,服务器响应 200(返回数据); 而对于 POST,浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data,服务器响应 200 ok(返回数据) 2、区别: - GET 参数通过 url 传递,POST 放在 request body 中。 - GET 请求在 url 中传递的参数是有长度限制的,而 POST 没有。 - GET 比 POST 更不安全,因为参数直接暴露在 url 中,所以不能用来传递敏感信息。 - GET 请求只能进行 url 编码,而 POST 支持多种编码方式。 - GET 请求会浏览器主动 cache,而 POST 支持多种编码方式。 - GET 请求参数会被完整保留在浏览历史记录里,而 POST 中的参数不会被保留。 - GET 和 POST 本质上就是 TCP 链接,并无差别。但是由于 HTTP 的规定和浏览器 / 服务器的限制,导致他们在应用过程中体现出一些不同。 - GET 产生一个 TCP 数据包;POST 产生两个 TCP 数据包。 如何设计数据库 **************************************** - 需求分析:了解用户的数据需求、处理需求、安全性及完整性要求; - 概念设计:通过数据抽象,设计系统概念模型,一般为 E-R 模型; - 逻辑结构设计:设计系统的模式和外模式,对于关系模型主要是基本表和视图; - 物理结构设计:设计数据的存储结构和存取方法,如索引的设计; - 系统实施:组织数据入库、编制应用程序、试运行; - 运行维护:系统投入运行,长期的维护工作。 三个范式 **************************************** 1NF:数据表中的所有码都是不可再分的 2NF:存在唯一一个主键,且其它关键字与主键一一对应 3NF:非主属性不依赖于非主键属性 数据库隔离级别 **************************************** +------------------+----------------------------------------------------------------------+ | 隔离级别 | 作用 | +==================+======================================================================+ | Read Uncommitted | 什么也不做 | +------------------+----------------------------------------------------------------------+ | Read Committed | 事务提交后才能读取数据,解决幻读 | +------------------+----------------------------------------------------------------------+ | Repeated Read | 在一个事务中,对同一份数据的读取结果总是相同的,解决脏读、解决重复读 | +------------------+----------------------------------------------------------------------+ | Serialization | 事务串行执行。通过牺牲系统的并发性解决并发事务的所有问题 | +------------------+----------------------------------------------------------------------+ 设计模式 **************************************** - 单例模式:解决一个全局使用的类频繁的创建和销毁的问题。单例模式有三个要素:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。 - 工厂模式:工厂模式主要解决接口选择的问题。该模式下定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,使其创建过程延迟到子类进行。例如选择数据库驱动 - 观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新 - 装饰器模式:对已经存在的某些类进行装饰,以此来扩展一些功能,从而动态的为一个对象增加新的功能 - 原型模式:解决对象的复制问题 .. note:: C++11 及以上使用 static 局部变量就可以实现 singleton 了,其初始化和线程安全性质由 c++ 语言规范保证 单例模式的优缺点 **************************************** 主要优点: - 提供了对唯一实例的受控访问 - 由于系统中内存只存在一个对象,因此可以节约系统的的资源 主要缺点: - 由于单例模式,不是抽象的所以可扩展性比较差 - 单例类,职责过重,在一定程度上违背了单一职责‘ - 滥用单例将带来一些负面的问题,如为了节省资源将数据库连接池对象设计为单例模式,可能会导致共享连接池对象的程序过多未出而出现的连接池溢出,如果实例化对象长时间不用系统就会被认为垃圾对象被回收,这将导致对象状态丢失。 单例模式中的饿汉式和懒汉式 **************************************** 懒汉式:在需要的时候才构造对象,除非加锁,否则线程不安全 饿汉式:在类装载的时候就实例化对象,线程安全,无需加锁。此功能由 C++ 保证 常用的 Linux 命令 **************************************** cat、grep、awk、sed、netstat、ip、firewall-cmd、systemctl、vim、top、ps 段错误的原因 **************************************** - 指针越界 - 栈溢出 - 迭代器失效 STL 五大组件 **************************************** - 容器 - 算法 - 迭代器 - 仿函数 - 适配器:就是栈 - 配置器:就是分配内存的 栈的底层实现默认是双端队列,但是只要满足 push_back、pop_back 等操作,使用其它容器也行 C++ 迭代器 **************************************** - 输入迭代器:允许读 - 输出迭代器:允许写 - 前向迭代器:允许自减操作 - 双向迭代器:允许双向操作 - 随机迭代器:允许跳转 new 和 malloc 的区别 **************************************** - new 按照数据类型分配内存,malloc 按照指定的大小分配内存 - new 返回的是指定对象的指针,而 malloc 返回的是 void\*,因此 malloc 的返回值一般都需要进行类型转化。 - new 会调用构造函数,malloc 不会。 - new 分配的内存要用 delete 销毁,malloc 要用 free 来销毁;delete 销毁的时候会调用对象的析构函数,而 free 则不会 - new 是一个操作符可以重载,malloc 是一个库函数 - malloc 分配的内存不够的时候,可以用 realloc 扩容。new 没用这样操作。 - new 如果分配失败了会抛出 bad_alloc 的异常,而 malloc 失败了会返回 NULL - 申请数组时: new[] 一次分配所有内存,多次调用构造函数,搭配使用 delete[],delete[] 多次调用析构函数,销毁数组中的每个对象。而 malloc 则只能 sizeof(int) * n。 多重继承以及其中存在的问题?多重继承内部是怎么实现的 ******************************************************************************** 菱形继承 基类对象的排列顺序和继承时声明的顺序相同 多态 **************************************** C++ 中的多态分为静态多态(函数重载)和动态多态(虚函数),此外还有模板带来的编译期多态(实际上也是函数重载的一种) .. seealso:: - `阻塞 IO 与非阻塞 IO_万年精魄的博客 `_ - `TCP的流量控制和拥塞控制 `_ ######################################## 测试开发 ######################################## Session、Cookie 和 Token **************************************** | Session 是存储在服务器端的,Cookie 是存储在客户端的 | Cookie 不安全 | Cookie 保存的数据不能超过 4KB,Session 则没有限制 | Cookie 的内容是名字、值、过期时间和域,但是 Session 则是键值对 | Cookie 即可以储存到内存中也可以储存到磁盘中 | Cookie 一个典型应用是购物车 | Session 通过 SessionID 识别用户,这样就无需在 Cookie 携带类似密码这样的敏感信息了 | Token 是无状态的,因此不会像 Session 这样由于负载均衡导致链接失效 | Tokens能够创建与其它程序共享权限的程序 | Token 是用户第一次登陆后服务器生成一个 Token。当后续客户发送数据的时候附带 Token 一起发送,服务端校验成功后返回数据。由于数据是明文的,因此不能保存敏感信息。而且 Token 和 SessionID、Cookie 一样可能被偷 | token 和 session 的验证机制最大的区别是用“签名验证机制”代替了“白名单验证机制” | Token 需要带上 user_id SessionID 可以直接被伪造,但是 Token 只能被偷取 Session是有生存期的,一般默认是20分钟。而 SessionID 会在浏览器关闭后被清除 .. seealso:: `前端鉴权必须了解的 5 个兄弟:cookie、session、token、jwt、单点登录 `_