字节一面总结
面试问题
1 线程和进程的区别
进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。
线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。
进程间通信方式:
- 管道
- 消息队列:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。
- 共享内存:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。
- 信号量: 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
- 套接字
- 信号
多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
2 死锁的原理
多个线程/进程在抢占CPU执行权的时候出现了互相等待的状态。
四个条件
这四个条件是死锁产生的必要条件,只要发生死锁,一定存在这四个条件
互斥条件 :一个资源每次只能被一个进程/线程使用
请求保持条件:一个进程在申请新的资源的同时保持对原有资源的占有(只有这样才是动态申请,动态分配);
循环等待:资源申请者不能强行地从资源占有者手中夺取资源,资源只能由占有者自愿释放;
不可抢占:若干进程之间形成一种头尾相连的循环等待资源。
3 url中输入HTTPS后的全流程
解析URL
检查这些请求是HTTPS还是HTTP,如果是HTTPS的话则使用HTTPS协议进行访问
查找IP地址
首先检查本地缓存中是否存在该域名,如果存在则直接使用缓存中的IP地址进行访问。
如果不存在,检查域名是否在本地的Hosts文件中,如果找到直接返回域名对应的IP。
向DNS服务器发送一个域名查询请求,然后就执行DNS查询过程,最终返回域名对应的IP地址。
建立连接
- 当浏览器得到了目标服务器的 IP 地址,以及 URL 中给出来端口号(http 协议默认端口号是 80, https 默认端口号是 443),它会调用系统库函数 socket ,请求一个 TCP流套接字。进行网络数据的传输。
- 连接建立之后,则根据HTTP协议进行数据交换,资源通常是 HTML 文件,也可能是 PDF,图片,或者其他类型的内容。
浏览器获得资源文件后,HTML,css,js等文件则根据自身内核的机制,进行页面渲染,然后呈现给用户。
浏览器发送连接请求,附上自己支持的加密算法
服务器接收到客户端请求,想浏览器发送对应的CA证书,证书包含非堆成加密的公钥以及证书签名。
浏览器判断证书是否合法,并生成随机会话密钥,使用公钥加密随机会话密钥后发送给服务器
服务器采用私钥解密随机会话密钥
4 cookie和session的区别
cookie数据保存在客户端,session数据保存在服务器端。
Cookie的工作原理:
(1)浏览器端第一次发送请求到服务器端
(2)服务器端创建Cookie,该Cookie中包含用户的信息,然后将该Cookie发送到浏览器端
(3)浏览器端再次访问服务器端时会携带服务器端创建的Cookie
(4)服务器端通过Cookie中携带的数据区分不同的用户
Session的工作原理:
(1)浏览器端第一次发送请求到服务器端,服务器端创建一个Session,同时会创建一个特殊的Cookie(name为JSESSIONID的固定值,value为session对象的ID),然后将该Cookie发送至浏览器端
(2)浏览器端发送第N(N>1)次请求到服务器端,浏览器端访问服务器端时就会携带该name为JSESSIONID的Cookie对象
(3)服务器端根据name为JSESSIONID的Cookie的value(sessionId),去查询Session对象,从而区分不同用户。
name为JSESSIONID的Cookie不存在(关闭或更换浏览器),返回1中重新去创建Session与特殊的Cookie
name为JSESSIONID的Cookie存在,根据value中的SessionId去寻找session对象
value为SessionId不存在(Session对象默认存活30分钟),返回1中重新去创建Session与特殊的Cookie
value为SessionId存在,返回session对象
区别:
cookie数据保存在客户端,session数据保存在服务端。
session
简单的说,当你登陆一个网站的时候,如果web服务器端使用的是session,那么所有的数据都保存在服务器上,客户端每次请求服务器的时候会发送当前会话sessionid,服务器根据当前sessionid判断相应的用户数据标志,以确定用户是否登陆或具有某种权限。由于数据是存储在服务器上面,所以你不能伪造。
cookie
sessionid是服务器和客户端连接时候随机分配的,如果浏览器使用的是cookie,那么所有数据都保存在浏览器端,比如你登陆以后,服务器设置了cookie用户名,那么当你再次请求服务器的时候,浏览器会将用户名一块发送给服务器,这些变量有一定的特殊标记。服务器会解释为cookie变量,所以只要不关闭浏览器,那么cookie变量一直是有效的,所以能够保证长时间不掉线。
5 MYSQL的索引
索引是存储引擎用于提高数据库表的访问速度的一种数据结构。
优点:
缺点:
- 建立索引需要占用物理空间
- 会降低表的增删改的效率,因为每次对表记录进行增删改,需要进行动态维护索引,导致增删改时间变长
作用:
数据是存储在磁盘上的,查询数据时,如果没有索引,会加载所有的数据到内存,依次进行检索,读取磁盘次数较多。有了索引,就不需要加载所有数据,因为B+树的高度一般在2-4层,最多只需要读取2-4次磁盘,查询速度大大提升。
建立索引的条件:
什么情况下不建索引?
where
条件中用不到的字段不适合建立索引- 表记录较少
- 需要经常增删改
- 参与列计算的列不适合建索引
- 区分度不高的字段不适合建立索引,如性别等
6 并列索引
ABC
查询AC只能部分命中,索引的部分命中
什么是最左匹配原则?
如果 SQL 语句中用到了组合索引中的最左边的索引,那么这条 SQL 语句就可以利用这个组合索引去进行匹配。当遇到范围查询(>
、<
、between
、like
)就会停止匹配,后面的字段不会用到索引。
对(a,b,c)
建立索引,查询条件使用 a/ab/abc 会走索引,使用 bc 不会走索引。
对(a,b,c,d)
建立索引,查询条件为a = 1 and b = 2 and c > 3 and d = 4
,那么a、b和c三个字段能用到索引,而d无法使用索引。因为遇到了范围查询。
如下图,对(a, b) 建立索引,a 在索引树中是全局有序的,而 b 是全局无序,局部有序(当a相等时,会根据b进行排序)。直接执行b = 2
这种查询条件无法使用索引。
当a的值确定的时候,b是有序的。例如a = 1
时,b值为1,2是有序的状态。当a = 2
时候,b的值为1,4也是有序状态。 当执行a = 1 and b = 2
时a和b字段能用到索引。而执行a > 1 and b = 2
时,a字段能用到索引,b字段用不到索引。因为a的值此时是一个范围,不是固定的,在这个范围内b值不是有序的,因此b字段无法使用索引。
7 抽象类和接口的区别
8 抽象类和接口分别在什么场景下使用
使用抽象类的情况:
- 需要为一些类提供公共的实现代码时,应优先考虑抽象类
- 定义某个领域的固有属性
- 既想约束子类具有共同的行为(但不再乎其如何实现),又想拥有缺省的方法,又能拥有实例变量
使用接口:
- 约束多个实现类具有统一的行为,但是不在乎每个实现类如何具体实现
- 实现类需要具备很多不同的功能,但各个功能之间可能没有任何联系。
- 使用接口的引用调用具体实现类中实现的方法(多态)
9 JVM垃圾回收机制、算法
垃圾收集器:Serial收集器
算法:
- 标记清除算法: 标记要回收的对象,标记完成后统一回收所有被标记的对象。效率问题、空间问题
- 复制算法:将内存分为两部分,每次使用一部分,使用完之后将存活对象拷贝到另一块内存当中,再将所有内存全部清除。
- 标记-整理算法:标记过程仍然与“标记-清除”算法⼀样,但后续步骤不是直接对可回收对象回收,⽽是让所有存活的对象向⼀端移动,然后直接清理掉端边界以外的内存 。
- 分代收集算法:⽐如在新⽣代中,每次收集都会有⼤量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。⽽⽼年代的对象存活⼏率是⽐较⾼的,⽽且没有额外的空间对它进⾏分
配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进⾏垃圾收集
10 JAVA中线程、进程同步方式
11 JAVA类的加载过程
- 加载
- 验证
- 准备
- 解析
- 初始化
- 使用
- 卸载
12.Linux中的内存模型
内存管理分为连续分配管理以及非连续分配管理两种
连续分配管理 :块式管理。
非连续分配管理:页式管理、段式管理以及段页式管理.
在分页式内存管理当中,由于存在虚拟内存,存在
- 虚拟地址到物理地址的转换要快。
- 解决虚拟地址空间⼤,⻚表也会很⼤的问题
为了解决虚拟地址到物理地址的转换速度,操作系统在 ⻚表⽅案 基础之上引⼊了 快表 来加速虚拟地
址到物理地址的转换。其中的内容是⻚表的⼀部分或者全部内容。作为⻚表的 Cache,它的作⽤与⻚表相似,但是提⾼了访问速率。由于采⽤⻚表做地址转换,读写内存数据时 CPU 要访问两次主存。有了快表,有时只要访问⼀次⾼速缓冲存储器,⼀次主存,这样可加速查找并提⾼指令执⾏速度。
- 根据虚拟地址中的⻚号查快表;
- 如果该⻚在快表中,直接从快表中读取相应的物理地址;
- 如果该⻚不在快表中,就访问内存中的⻚表,再从⻚表中得到物理地址,同时将⻚表中的该映射
表项添加到快表中; - 当快表填满后,⼜要登记新⻚时,就按照⼀定的淘汰策略淘汰掉快表中的⼀个⻚。
算法
题目
给定一个数n如23121;给定一组数字a如[2 4 9]求由a中元素组成的小于n的最大数
代码解析思路
该题使用到的算法主要是贪心、回溯以及二分,首先将nums数组进行排序方便进行二分查找,之后将给定数字n分解成一个列表,注意最高位在列表的最后一位,需要从前往后尽心寻找。
首先判断能取的最大数跟N的位数是否相同,不同直接取数组中的最大值即可。
注意如果出现前面取跟n一样的数,而后面出现没有数可以取的情况需要回溯减小前面的数。
代码
1 |
|
测试案例
1 |
|
输出结果
1 |
|