专栏名称: 程序员书库
程序员十点读书,每晚 22:00 推送,为程序员介绍好书,程序员书单~~~
目录
相关文章推荐
英国大家谈  ·  250万人民币葡萄牙护照到手! ·  2 天前  
建E室内设计网  ·  私宅设计:800㎡自然风别墅,心灵栖息的世外桃源! ·  2 天前  
建E室内设计网  ·  建E首发 | UHOUSE ... ·  4 天前  
gooood谷德设计网  ·  昆明招聘 | 素造建筑 SUZAO – ... ·  3 天前  
51好读  ›  专栏  ›  程序员书库

等不及,冲滴滴去了!

程序员书库  · 公众号  ·  · 2024-02-28 22:13

正文

来自公众号: 小林coding

发现现在校招同学都好卷,为了能毕业找到不错的工作,在校期间都会积累多段实习经历,甚至有同学大二开始卷实习经历了。

从结果来看,确实有实习经历的同学,在找工作的时候,也会更顺利一些。有了实习经历后,在秋招过程中也会比较顺利,积累多个中大实习的话,秋招获得 sp、ssp offer 的概率会比较大一些。

对于大厂的实习面试,还是八股文+项目+算法这三大块的面试范围。

对于Java 同学来说,Java 基础+Java 并发+Java 容器+JVM+MySQL+Redis+1~2 个后端项目+网络+系统+算法,这几大块知识的常规八股文准备好,就基本可以尝试投实习了,通常来说越早投实习,越不卷,通过率也会比较高。

所以,25 届的同学可以准备学习,准备找实习了,很多 25 届还不知道面试的具体范围。

今天就来分享一位研二 Java 同学面试 滴滴实习的面经, 主要是问了Java+Redis&MySQL+系统&网络+算法+项目,都是比较经典面试题,收藏起来,反复复习!

操作系统

线程和协程有什么区别?

  • 调度方式:线程的调度由操作系统内核负责,采用的是抢占式调度,即操作系统可以主动剥夺线程的执行权。而协程的调度由用户程序控制,采用的是协作式调度,即协程主动让出执行权。
  • 切换开销:线程切换需要从用户态切换到内核态,涉及CPU寄存器的保存和恢复等操作,开销较大。而协程切换是在用户态进行的,开销较小。
  • 内存开销:线程的创建和销毁涉及操作系统的调用和资源分配,开销较大。而协程的创建和销毁由用户程序控制,开销较小。

为什么协程切换的开销比线程切换小?

  • 用户态切换:协程的切换是在用户态进行的,不需要操作系统的介入。相比之下,线程的切换需要操作系统进行调度和上下文切换,需要从用户态切换到内核态,这涉及到CPU寄存器的保存和恢复等操作,开销较大。
  • 协作式调度:协程的调度是协作式的,由协程自身主动让出执行权,而不是被操作系统强制切换。这种调度方式避免了不必要的上下文切换,减少了切换开销。

进程和线程的区别?

图片
  • 本质区别 :进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
  • 在开销方面 :每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小
  • 所处环境 :在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)
  • 内存分配方面 :系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源
  • 包含关系 :没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程

举个例子:进程=火车,线程=车厢

  • 线程在进程下行进(单纯的车厢无法运行)
  • 一个进程可以包含多个线程(一辆火车可以有多个车厢)
  • 不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)
  • 同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)
  • 进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)
  • 进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)

多线程是不是越多越好,太多会有什么问题?

多线程不一定越多越好,过多的线程可能会导致一些问题。

  • 切换开销:线程的创建和切换会消耗系统资源,包括内存和CPU。如果创建太多线程,会占用大量的系统资源,导致系统负载过高,某个线程崩溃后,可能会导致进程崩溃。
  • 死锁的问题:过多的线程可能会导致竞争条件和死锁。竞争条件指的是多个线程同时访问和修改共享资源,如果没有合适的同步机制,可能会导致数据不一致或错误的结果。而死锁则是指多个线程相互等待对方释放资源,导致程序无法继续执行。

知道fork吗?

知道的,fork是创建子进程的系统调用方法。

#include 

int main() {
    pid_t child_pid;

    child_pid = fork();

    if (child_pid == 0) {
        // 子进程逻辑
    } else if (child_pid > 0) {
        // 父进程逻辑
    } else {
        // fork失败的处理逻辑
    }

    return 0;
}

多个进程的资源是共享的还是隔离的?

多个进程的资源是隔离的。每个进程有自己独立的内存空间,不能直接访问其他进程的内存。进程也有自己的文件描述符表、网络连接等资源,这些资源也是独立的,不会被其他进程访问或影响。

一个进程的所有内存资源对于线程都是共享的吗?

在同一个进程中的多个线程共享相同的内存空间,包括代码段、数据段、堆和共享库等。这意味着线程可以直接访问进程的全局变量、静态变量和动态分配的内存等资源。

不过,线程也有自己的栈空间。每个线程在栈上分配自己的局部变量和函数调用信息,这些是线程私有的。栈空间在每个线程之间是隔离的,不会被其他线程访问。这意味着每个线程拥有自己的栈帧和栈指针。

一个进程fork出一个子进程,那么他们占用的内存是之前的2倍吗?

不是的。

fork 的时候,创建的子进程是复父进程的虚拟内存,并不是物理内存,这时候父子的虚拟内存指向的是同一个物理内存空间,这样能够 节约物理内存资源 ,页表对应的页表项的属性会标记该物理内存的权限为 只读

不过,当父进程或者子进程在向这个内存发起写操作时,CPU 就会触发 写保护中断 ,这个写保护中断是由于违反权限导致的,然后操作系统会在「写保护中断处理函数」里进行 物理内存的复制 ,并重新设置其内存映射关系,将父子进程的内存读写权限设置为 可读写 ,最后才会对内存进行写操作,这个过程被称为「 写时复制 」。

img

写时复制顾名思义, 在发生写操作的时候,操作系统才会去复制物理内存

网络

DNS是什么?

DNS主要的作用是将将域名(例如www.example.com)转换为对应IP地址(例如192.0.2.1)。它充当了互联网上的电话簿,将人们熟悉的域名转换为机器可识别的IP地址。

域名解析的工作流程

  1. 客户端首先会发出一个 DNS 请求,问 www.server.com 的 IP 是啥,并发给本地 DNS 服务器(也就是客户端的 TCP/IP 设置中填写的 DNS 服务器地址)。
  2. 本地域名服务器收到客户端的请求后,如果缓存里的表格能找到 www.server.com,则它直接返回 IP 地址。如果没有,本地 DNS 会去问它的根域名服务器:“老大, 能告诉我 www.server.com 的 IP 地址吗?” 根域名服务器是最高层次的,它不直接用于域名解析,但能指明一条道路。
  3. 根 DNS 收到来自本地 DNS 的请求后,发现后置是 .com,说:“www.server.com 这个域名归 .com 区域管理”,我给你 .com 顶级域名服务器地址给你,你去问问它吧。”
  4. 本地 DNS 收到顶级域名服务器的地址后,发起请求问“老二, 你能告诉我 www.server.com 的 IP 地址吗?”
  5. 顶级域名服务器说:“我给你负责 www.server.com 区域的权威 DNS 服务器的地址,你去问它应该能问到”。
  6. 本地 DNS 于是转向问权威 DNS 服务器:“老三,www.server.com对应的IP是啥呀?” server.com 的权威 DNS 服务器,它是域名解析结果的原出处。为啥叫权威呢?就是我的域名我做主。
  7. 权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。
  8. 本地 DNS 再将 IP 地址返回客户端,客户端和目标建立连接。

至此,我们完成了 DNS 的解析过程。现在总结一下,整个过程我画成了一个图。

域名解析的工作流程

DNS域名解析使用的什么协议?

DNS域名解析使用的是UDP协议。在DNS中,域名解析请求和响应都是基于UDP进行传输的。

UDP是一种无连接的、不可靠的传输层协议,它提供了一种简单的传输机制,适用于对实时性要求较高的应用场景。DNS使用UDP协议进行域名解析是因为域名解析通常是短小而频繁的请求,UDP的无连接特性可以减少建立和断开连接的开销,并提高解析的效率。

UDP对于TCP有什么缺点?在这个业务里怎么解决?

UDP对于TCP的缺点是没办法保证数据的可靠传输,针对这个缺陷,可以在应用层实现一个超时重传机制,如果域名解析请求在一定时间内没收到响应,那么就重发域名解析请求。

ping命令用的什么协议?

用的是ICMP协议。

ICMP 主要的功能包括: 确认 IP 包是否成功送达目标地址、报告发送过程中 IP 包被废弃的原因和改善网络设置等。

ICMP 回送消息

它为什么用ICMP不用UDP?

ICMP是在网络层,UDP是在传输层。

因为ping命令是不需要传输数据的,只需要一个 true/false 的结果,所以根本没必要用传输层的UDP协议。

Redis&MySQL

Redis为什么这么快?

官方使用基准测试的结果是, 单线程的 Redis 吞吐量可以达到 10W/每秒 ,如下图所示:

img

之所以 Redis 采用单线程(网络 I/O 和执行命令)那么快,有如下几个原因:

  • Redis 的大部分操作 都在内存中完成 ,并且采用了高效的数据结构,因此 Redis 瓶颈可能是机器的内存或者网络带宽,而并非 CPU,既然 CPU 不是瓶颈,那么自然就采用单线程的解决方案了;
  • Redis 采用单线程模型可以 避免了多线程之间的竞争 ,省去了多线程切换带来的时间和性能上的开销,而且也不会导致死锁问题。
  • Redis 采用了 I/O 多路复用机制 处理大量的客户端 Socket 请求,IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听 Socket 和已连接 Socket。内核会一直监听这些 Socket 上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。

建立联合索引有什么需要注意的?

建立联合索引时的字段顺序,对索引效率也有很大影响。越靠前的字段被用于索引过滤的概率越高,实际开发工作中 建立联合索引时,要把区分度大的字段排在前面,这样区分度大的字段越有可能被更多的 SQL 使用到

区分度就是某个字段 column 不同值的个数「除以」表的总行数,计算公式如下:

区分度计算公式

比如,性别的区分度就很小,不适合建立索引或不适合排在联合索引列的靠前的位置,而 UUID 这类字段就比较适合做索引或排在联合索引列的靠前的位置。

因为如果索引的区分度很小,假设字段的值分布均匀,那么无论搜索哪个值都可能得到一半的数据。在这些情况下,还不如不要索引,因为 MySQL 还有一个查询优化器,查询优化器发现某个值出现在表的数据行中的百分比(惯用的百分比界线是"30%")很高的时候,它一般会忽略索引,进行全表扫描。

mysql索引失效原因有哪些?

  • 当我们使用左或者左右模糊匹配的时候,也就是 like %xx 或者 like %xx% 这两种方式都会造成索引失效;
  • 当我们在查询条件中对索引列使用函数,就会导致索引失效。
  • 当我们在查询条件中对索引列进行表达式计算,也是无法走索引的。
  • MySQL 在遇到字符串和数字比较的时候,会自动把字符串转为数字,然后再进行比较。如果字符串是索引列,而条件语句中的输入参数是数字的话,那么索引列会发生隐式类型转换,由于隐式类型转换是通过 CAST 函数实现的,等同于对索引列使用了函数,所以就会导致索引失效。
  • 联合索引要能正确使用需要遵循最左匹配原则,也就是按照最左优先的方式进行索引的匹配,否则就会导致索引失效。






请到「今天看啥」查看全文